FreeWRL / FreeX3D 4.3.0
duktape.c
1/*
2 * Single source autogenerated distributable for Duktape 2.0.0.
3 *
4 * Git commit external (external).
5 * Git branch external.
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-2017 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*
86* Other contributions
87* ===================
88*
89* The following people have contributed something other than code (e.g. reported
90* bugs, provided ideas, etc; roughly in order of appearance):
91*
92* * Greg Burns
93* * Anthony Rabine
94* * Carlos Costa
95* * Aur\u00e9lien Bouilland
96* * Preet Desai (Pris Matic)
97* * judofyr (http://www.reddit.com/user/judofyr)
98* * Jason Woofenden
99* * Micha\u0142 Przyby\u015b
100* * Anthony Howe
101* * Conrad Pankoff
102* * Jim Schimpf
103* * Rajaran Gaunker (https://github.com/zimbabao)
104* * Andreas \u00d6man
105* * Doug Sanden
106* * Josh Engebretson (https://github.com/JoshEngebretson)
107* * Remo Eichenberger (https://github.com/remoe)
108* * Mamod Mehyar (https://github.com/mamod)
109* * David Demelier (https://github.com/markand)
110* * Tim Caswell (https://github.com/creationix)
111* * Mitchell Blank Jr (https://github.com/mitchblank)
112* * https://github.com/yushli
113* * Seo Sanghyeon (https://github.com/sanxiyn)
114* * Han ChoongWoo (https://github.com/tunz)
115* * Joshua Peek (https://github.com/josh)
116* * Bruce E. Pascoe (https://github.com/fatcerberus)
117* * https://github.com/Kelledin
118* * https://github.com/sstruchtrup
119* * Michael Drake (https://github.com/tlsa)
120* * https://github.com/chris-y
121* * Laurent Zubiaur (https://github.com/lzubiaur)
122* * Neil Kolban (https://github.com/nkolban)
123*
124* If you are accidentally missing from this list, send me an e-mail
125* (``sami.vaarala@iki.fi``) and I'll fix the omission.
126*/
127
128/*
129 * Replacements for missing platform functions.
130 *
131 * Unlike the originals, fpclassify() and signbit() replacements don't
132 * work on any floating point types, only doubles. The C typing here
133 * mimics the standard prototypes.
134 */
135
136/* #include duk_internal.h */
137/*
138 * Top-level include file to be used for all (internal) source files.
139 *
140 * Source files should not include individual header files, as they
141 * have not been designed to be individually included.
142 */
143
144#if !defined(DUK_INTERNAL_H_INCLUDED)
145#define DUK_INTERNAL_H_INCLUDED
146
147/*
148 * The 'duktape.h' header provides the public API, but also handles all
149 * compiler and platform specific feature detection, Duktape feature
150 * resolution, inclusion of system headers, etc. These have been merged
151 * because the public API is also dependent on e.g. detecting appropriate
152 * C types which is quite platform/compiler specific especially for a non-C99
153 * build. The public API is also dependent on the resolved feature set.
154 *
155 * Some actions taken by the merged header (such as including system headers)
156 * are not appropriate for building a user application. The define
157 * DUK_COMPILING_DUKTAPE allows the merged header to skip/include some
158 * sections depending on what is being built.
159 */
160
161#define DUK_COMPILING_DUKTAPE
162#include "duktape.h"
163
164/*
165 * User declarations, e.g. prototypes for user functions used by Duktape
166 * macros.
167 */
168
169DUK_USE_USER_DECLARE()
170
171/*
172 * Duktape includes (other than duk_features.h)
173 *
174 * The header files expect to be included in an order which satisfies header
175 * dependencies correctly (the headers themselves don't include any other
176 * includes). Forward declarations are used to break circular struct/typedef
177 * dependencies.
178 */
179
180/* #include duk_replacements.h */
181#if !defined(DUK_REPLACEMENTS_H_INCLUDED)
182#define DUK_REPLACEMENTS_H_INCLUDED
183
184#if !defined(DUK_SINGLE_FILE)
185#if defined(DUK_USE_COMPUTED_INFINITY)
186DUK_INTERNAL_DECL double duk_computed_infinity;
187#endif
188#if defined(DUK_USE_COMPUTED_NAN)
189DUK_INTERNAL_DECL double duk_computed_nan;
190#endif
191#endif /* !DUK_SINGLE_FILE */
192
193#if defined(DUK_USE_REPL_FPCLASSIFY)
194DUK_INTERNAL_DECL int duk_repl_fpclassify(double x);
195#endif
196#if defined(DUK_USE_REPL_SIGNBIT)
197DUK_INTERNAL_DECL int duk_repl_signbit(double x);
198#endif
199#if defined(DUK_USE_REPL_ISFINITE)
200DUK_INTERNAL_DECL int duk_repl_isfinite(double x);
201#endif
202#if defined(DUK_USE_REPL_ISNAN)
203DUK_INTERNAL_DECL int duk_repl_isnan(double x);
204#endif
205#if defined(DUK_USE_REPL_ISINF)
206DUK_INTERNAL_DECL int duk_repl_isinf(double x);
207#endif
208
209#endif /* DUK_REPLACEMENTS_H_INCLUDED */
210/* #include duk_jmpbuf.h */
211/*
212 * Wrapper for jmp_buf.
213 *
214 * This is used because jmp_buf is an array type for backward compatibility.
215 * Wrapping jmp_buf in a struct makes pointer references, sizeof, etc,
216 * behave more intuitively.
217 *
218 * http://en.wikipedia.org/wiki/Setjmp.h#Member_types
219 */
220
221#if !defined(DUK_JMPBUF_H_INCLUDED)
222#define DUK_JMPBUF_H_INCLUDED
223
224#if defined(DUK_USE_CPP_EXCEPTIONS)
225struct duk_jmpbuf {
226 duk_small_int_t dummy; /* unused */
227};
228#else
230 DUK_JMPBUF_TYPE jb;
231};
232#endif
233
234#endif /* DUK_JMPBUF_H_INCLUDED */
235/* #include duk_exception.h */
236/*
237 * Exception for Duktape internal throws when C++ exceptions are used
238 * for long control transfers.
239 *
240 * Doesn't inherit from any exception base class to minimize the chance
241 * that user code would accidentally catch this exception.
242 */
243
244#if !defined(DUK_EXCEPTION_H_INCLUDED)
245#define DUK_EXCEPTION_H_INCLUDED
246
247#if defined(DUK_USE_CPP_EXCEPTIONS)
248class duk_internal_exception {
249 /* intentionally empty */
250};
251#endif
252
253#endif /* DUK_EXCEPTION_H_INCLUDED */
254/* #include duk_forwdecl.h */
255/*
256 * Forward declarations for all Duktape structures.
257 */
258
259#if !defined(DUK_FORWDECL_H_INCLUDED)
260#define DUK_FORWDECL_H_INCLUDED
261
262/*
263 * Forward declarations
264 */
265
266#if defined(DUK_USE_CPP_EXCEPTIONS)
267class duk_internal_exception;
268#else
269struct duk_jmpbuf;
270#endif
271
272/* duk_tval intentionally skipped */
273struct duk_heaphdr;
274struct duk_heaphdr_string;
275struct duk_harray;
276struct duk_hstring;
278struct duk_hobject;
279struct duk_hcompfunc;
280struct duk_hnatfunc;
281struct duk_hthread;
282struct duk_hbufobj;
283struct duk_hbuffer;
284struct duk_hbuffer_fixed;
287
288struct duk_propaccessor;
289union duk_propvalue;
290struct duk_propdesc;
291
292struct duk_heap;
293struct duk_breakpoint;
294
295struct duk_activation;
296struct duk_catcher;
297struct duk_strcache;
298struct duk_ljstate;
299struct duk_strtab_entry;
300
301#if defined(DUK_USE_DEBUG)
302struct duk_fixedbuffer;
303#endif
304
305struct duk_bitdecoder_ctx;
306struct duk_bitencoder_ctx;
307struct duk_bufwriter_ctx;
308
309struct duk_token;
310struct duk_re_token;
311struct duk_lexer_point;
312struct duk_lexer_ctx;
314
315struct duk_compiler_instr;
316struct duk_compiler_func;
317struct duk_compiler_ctx;
318
319struct duk_re_matcher_ctx;
321
322#if defined(DUK_USE_CPP_EXCEPTIONS)
323/* no typedef */
324#else
325typedef struct duk_jmpbuf duk_jmpbuf;
326#endif
327
328/* duk_tval intentionally skipped */
329typedef struct duk_heaphdr duk_heaphdr;
331typedef struct duk_harray duk_harray;
332typedef struct duk_hstring duk_hstring;
334typedef struct duk_hobject duk_hobject;
335typedef struct duk_hcompfunc duk_hcompfunc;
336typedef struct duk_hnatfunc duk_hnatfunc;
337typedef struct duk_hbufobj duk_hbufobj;
338typedef struct duk_hthread duk_hthread;
339typedef struct duk_hbuffer duk_hbuffer;
343
345typedef union duk_propvalue duk_propvalue;
346typedef struct duk_propdesc duk_propdesc;
347
348typedef struct duk_heap duk_heap;
349typedef struct duk_breakpoint duk_breakpoint;
350
351typedef struct duk_activation duk_activation;
352typedef struct duk_catcher duk_catcher;
353typedef struct duk_strcache duk_strcache;
354typedef struct duk_ljstate duk_ljstate;
356
357#if defined(DUK_USE_DEBUG)
358typedef struct duk_fixedbuffer duk_fixedbuffer;
359#endif
360
364
365typedef struct duk_token duk_token;
366typedef struct duk_re_token duk_re_token;
367typedef struct duk_lexer_point duk_lexer_point;
368typedef struct duk_lexer_ctx duk_lexer_ctx;
370
374
377
378#endif /* DUK_FORWDECL_H_INCLUDED */
379/* #include duk_tval.h */
380/*
381 * Tagged type definition (duk_tval) and accessor macros.
382 *
383 * Access all fields through the accessor macros, as the representation
384 * is quite tricky.
385 *
386 * There are two packed type alternatives: an 8-byte representation
387 * based on an IEEE double (preferred for compactness), and a 12-byte
388 * representation (portability). The latter is needed also in e.g.
389 * 64-bit environments (it usually pads to 16 bytes per value).
390 *
391 * Selecting the tagged type format involves many trade-offs (memory
392 * use, size and performance of generated code, portability, etc).
393 *
394 * NB: because macro arguments are often expressions, macros should
395 * avoid evaluating their argument more than once.
396 */
397
398#if !defined(DUK_TVAL_H_INCLUDED)
399#define DUK_TVAL_H_INCLUDED
400
401/* sanity */
402#if !defined(DUK_USE_DOUBLE_LE) && !defined(DUK_USE_DOUBLE_ME) && !defined(DUK_USE_DOUBLE_BE)
403#error unsupported: cannot determine byte order variant
404#endif
405
406#if defined(DUK_USE_PACKED_TVAL)
407/* ======================================================================== */
408
409/*
410 * Packed 8-byte representation
411 */
412
413/* use duk_double_union as duk_tval directly */
414typedef union duk_double_union duk_tval;
415typedef struct {
416 duk_uint16_t a;
417 duk_uint16_t b;
418 duk_uint16_t c;
419 duk_uint16_t d;
421
422/* tags */
423#define DUK_TAG_NORMALIZED_NAN 0x7ff8UL /* the NaN variant we use */
424/* avoid tag 0xfff0, no risk of confusion with negative infinity */
425#define DUK_TAG_MIN 0xfff1UL
426#if defined(DUK_USE_FASTINT)
427#define DUK_TAG_FASTINT 0xfff1UL /* embed: integer value */
428#endif
429#define DUK_TAG_UNUSED 0xfff2UL /* marker; not actual tagged value */
430#define DUK_TAG_UNDEFINED 0xfff3UL /* embed: nothing */
431#define DUK_TAG_NULL 0xfff4UL /* embed: nothing */
432#define DUK_TAG_BOOLEAN 0xfff5UL /* embed: 0 or 1 (false or true) */
433/* DUK_TAG_NUMBER would logically go here, but it has multiple 'tags' */
434#define DUK_TAG_POINTER 0xfff6UL /* embed: void ptr */
435#define DUK_TAG_LIGHTFUNC 0xfff7UL /* embed: func ptr */
436#define DUK_TAG_STRING 0xfff8UL /* embed: duk_hstring ptr */
437#define DUK_TAG_OBJECT 0xfff9UL /* embed: duk_hobject ptr */
438#define DUK_TAG_BUFFER 0xfffaUL /* embed: duk_hbuffer ptr */
439#define DUK_TAG_MAX 0xfffaUL
440
441/* for convenience */
442#define DUK_XTAG_BOOLEAN_FALSE 0xfff50000UL
443#define DUK_XTAG_BOOLEAN_TRUE 0xfff50001UL
444
445#define DUK_TVAL_IS_VALID_TAG(tv) \
446 (DUK_TVAL_GET_TAG((tv)) - DUK_TAG_MIN <= DUK_TAG_MAX - DUK_TAG_MIN)
447
448/* DUK_TVAL_UNUSED initializer for duk_tval_unused, works for any endianness. */
449#define DUK_TVAL_UNUSED_INITIALIZER() \
450 { DUK_TAG_UNUSED, DUK_TAG_UNUSED, DUK_TAG_UNUSED, DUK_TAG_UNUSED }
451
452/* two casts to avoid gcc warning: "warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]" */
453#if defined(DUK_USE_64BIT_OPS)
454#if defined(DUK_USE_DOUBLE_ME)
455#define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag) do { \
456 (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 16) | (((duk_uint64_t) (duk_uint32_t) (h)) << 32); \
457 } while (0)
458#else
459#define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag) do { \
460 (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) (tag)) << 48) | ((duk_uint64_t) (duk_uint32_t) (h)); \
461 } while (0)
462#endif
463#else /* DUK_USE_64BIT_OPS */
464#define DUK__TVAL_SET_TAGGEDPOINTER(tv,h,tag) do { \
465 duk_tval *duk__tv; \
466 duk__tv = (tv); \
467 duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) (tag)) << 16; \
468 duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (h); \
469 } while (0)
470#endif /* DUK_USE_64BIT_OPS */
471
472#if defined(DUK_USE_64BIT_OPS)
473/* Double casting for pointer to avoid gcc warning (cast from pointer to integer of different size) */
474#if defined(DUK_USE_DOUBLE_ME)
475#define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \
476 (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 16) | \
477 ((duk_uint64_t) (flags)) | \
478 (((duk_uint64_t) (duk_uint32_t) (fp)) << 32); \
479 } while (0)
480#else
481#define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \
482 (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_LIGHTFUNC) << 48) | \
483 (((duk_uint64_t) (flags)) << 32) | \
484 ((duk_uint64_t) (duk_uint32_t) (fp)); \
485 } while (0)
486#endif
487#else /* DUK_USE_64BIT_OPS */
488#define DUK__TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \
489 duk_tval *duk__tv; \
490 duk__tv = (tv); \
491 duk__tv->ui[DUK_DBL_IDX_UI0] = (((duk_uint32_t) DUK_TAG_LIGHTFUNC) << 16) | ((duk_uint32_t) (flags)); \
492 duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (fp); \
493 } while (0)
494#endif /* DUK_USE_64BIT_OPS */
495
496#if defined(DUK_USE_FASTINT)
497/* Note: masking is done for 'i' to deal with negative numbers correctly */
498#if defined(DUK_USE_DOUBLE_ME)
499#define DUK__TVAL_SET_I48(tv,i) do { \
500 duk_tval *duk__tv; \
501 duk__tv = (tv); \
502 duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16 | (((duk_uint32_t) ((i) >> 32)) & 0x0000ffffUL); \
503 duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \
504 } while (0)
505#define DUK__TVAL_SET_U32(tv,i) do { \
506 duk_tval *duk__tv; \
507 duk__tv = (tv); \
508 duk__tv->ui[DUK_DBL_IDX_UI0] = ((duk_uint32_t) DUK_TAG_FASTINT) << 16; \
509 duk__tv->ui[DUK_DBL_IDX_UI1] = (duk_uint32_t) (i); \
510 } while (0)
511#else
512#define DUK__TVAL_SET_I48(tv,i) do { \
513 (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (((duk_uint64_t) (i)) & 0x0000ffffffffffffULL); \
514 } while (0)
515#define DUK__TVAL_SET_U32(tv,i) do { \
516 (tv)->ull[DUK_DBL_IDX_ULL0] = (((duk_uint64_t) DUK_TAG_FASTINT) << 48) | (duk_uint64_t) (i); \
517 } while (0)
518#endif
519
520/* This needs to go through a cast because sign extension is needed. */
521#define DUK__TVAL_SET_I32(tv,i) do { \
522 duk_int64_t duk__tmp = (duk_int64_t) (i); \
523 DUK_TVAL_SET_I48((tv), duk__tmp); \
524 } while (0)
525
526/* XXX: Clumsy sign extend and masking of 16 topmost bits. */
527#if defined(DUK_USE_DOUBLE_ME)
528#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)
529#else
530#define DUK__TVAL_GET_FASTINT(tv) ((((duk_int64_t) (tv)->ull[DUK_DBL_IDX_ULL0]) << 16) >> 16)
531#endif
532#define DUK__TVAL_GET_FASTINT_U32(tv) ((tv)->ui[DUK_DBL_IDX_UI1])
533#define DUK__TVAL_GET_FASTINT_I32(tv) ((duk_int32_t) (tv)->ui[DUK_DBL_IDX_UI1])
534#endif /* DUK_USE_FASTINT */
535
536#define DUK_TVAL_SET_UNDEFINED(tv) do { \
537 (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNDEFINED; \
538 } while (0)
539#define DUK_TVAL_SET_UNUSED(tv) do { \
540 (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_UNUSED; \
541 } while (0)
542#define DUK_TVAL_SET_NULL(tv) do { \
543 (tv)->us[DUK_DBL_IDX_US0] = (duk_uint16_t) DUK_TAG_NULL; \
544 } while (0)
545
546#define DUK_TVAL_SET_BOOLEAN(tv,val) DUK_DBLUNION_SET_HIGH32((tv), (((duk_uint32_t) DUK_TAG_BOOLEAN) << 16) | ((duk_uint32_t) (val)))
547
548#define DUK_TVAL_SET_NAN(tv) DUK_DBLUNION_SET_NAN_FULL((tv))
549
550/* Assumes that caller has normalized NaNs, otherwise trouble ahead. */
551#if defined(DUK_USE_FASTINT)
552#define DUK_TVAL_SET_DOUBLE(tv,d) do { \
553 duk_double_t duk__dblval; \
554 duk__dblval = (d); \
555 DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \
556 DUK_DBLUNION_SET_DOUBLE((tv), duk__dblval); \
557 } while (0)
558#define DUK_TVAL_SET_I48(tv,i) DUK__TVAL_SET_I48((tv), (i))
559#define DUK_TVAL_SET_I32(tv,i) DUK__TVAL_SET_I32((tv), (i))
560#define DUK_TVAL_SET_U32(tv,i) DUK__TVAL_SET_U32((tv), (i))
561#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) duk_tval_set_number_chkfast_fast((tv), (d))
562#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) duk_tval_set_number_chkfast_slow((tv), (d))
563#define DUK_TVAL_SET_NUMBER(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d))
564#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { \
565 duk_tval *duk__tv; \
566 duk_double_t duk__d; \
567 duk__tv = (tv); \
568 if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
569 duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
570 DUK_TVAL_SET_NUMBER_CHKFAST_FAST(duk__tv, duk__d); \
571 } \
572 } while (0)
573#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { \
574 duk_tval *duk__tv; \
575 duk_double_t duk__d; \
576 duk__tv = (tv); \
577 if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
578 duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
579 DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(duk__tv, duk__d); \
580 } \
581 } while (0)
582#else /* DUK_USE_FASTINT */
583#define DUK_TVAL_SET_DOUBLE(tv,d) do { \
584 duk_double_t duk__dblval; \
585 duk__dblval = (d); \
586 DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); \
587 DUK_DBLUNION_SET_DOUBLE((tv), duk__dblval); \
588 } while (0)
589#define DUK_TVAL_SET_I48(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i)) /* XXX: fast int-to-double */
590#define DUK_TVAL_SET_I32(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i))
591#define DUK_TVAL_SET_U32(tv,i) DUK_TVAL_SET_DOUBLE((tv), (duk_double_t) (i))
592#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d))
593#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d))
594#define DUK_TVAL_SET_NUMBER(tv,d) DUK_TVAL_SET_DOUBLE((tv), (d))
595#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { } while (0)
596#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { } while (0)
597#endif /* DUK_USE_FASTINT */
598
599#define DUK_TVAL_SET_FASTINT(tv,i) DUK_TVAL_SET_I48((tv), (i)) /* alias */
600
601#define DUK_TVAL_SET_LIGHTFUNC(tv,fp,flags) DUK__TVAL_SET_LIGHTFUNC((tv), (fp), (flags))
602#define DUK_TVAL_SET_STRING(tv,h) DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_STRING)
603#define DUK_TVAL_SET_OBJECT(tv,h) DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_OBJECT)
604#define DUK_TVAL_SET_BUFFER(tv,h) DUK__TVAL_SET_TAGGEDPOINTER((tv), (h), DUK_TAG_BUFFER)
605#define DUK_TVAL_SET_POINTER(tv,p) DUK__TVAL_SET_TAGGEDPOINTER((tv), (p), DUK_TAG_POINTER)
606
607#define DUK_TVAL_SET_TVAL(tv,x) do { *(tv) = *(x); } while (0)
608
609/* getters */
610#define DUK_TVAL_GET_BOOLEAN(tv) ((duk_small_int_t) (tv)->us[DUK_DBL_IDX_US1])
611#if defined(DUK_USE_FASTINT)
612#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->d)
613#define DUK_TVAL_GET_FASTINT(tv) DUK__TVAL_GET_FASTINT((tv))
614#define DUK_TVAL_GET_FASTINT_U32(tv) DUK__TVAL_GET_FASTINT_U32((tv))
615#define DUK_TVAL_GET_FASTINT_I32(tv) DUK__TVAL_GET_FASTINT_I32((tv))
616#define DUK_TVAL_GET_NUMBER(tv) duk_tval_get_number_packed((tv))
617#else
618#define DUK_TVAL_GET_NUMBER(tv) ((tv)->d)
619#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->d)
620#endif
621#define DUK_TVAL_GET_LIGHTFUNC(tv,out_fp,out_flags) do { \
622 (out_flags) = (tv)->ui[DUK_DBL_IDX_UI0] & 0xffffUL; \
623 (out_fp) = (duk_c_function) (tv)->ui[DUK_DBL_IDX_UI1]; \
624 } while (0)
625#define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv) ((duk_c_function) ((tv)->ui[DUK_DBL_IDX_UI1]))
626#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) (((duk_small_int_t) (tv)->ui[DUK_DBL_IDX_UI0]) & 0xffffUL)
627#define DUK_TVAL_GET_STRING(tv) ((duk_hstring *) (tv)->vp[DUK_DBL_IDX_VP1])
628#define DUK_TVAL_GET_OBJECT(tv) ((duk_hobject *) (tv)->vp[DUK_DBL_IDX_VP1])
629#define DUK_TVAL_GET_BUFFER(tv) ((duk_hbuffer *) (tv)->vp[DUK_DBL_IDX_VP1])
630#define DUK_TVAL_GET_POINTER(tv) ((void *) (tv)->vp[DUK_DBL_IDX_VP1])
631#define DUK_TVAL_GET_HEAPHDR(tv) ((duk_heaphdr *) (tv)->vp[DUK_DBL_IDX_VP1])
632
633/* decoding */
634#define DUK_TVAL_GET_TAG(tv) ((duk_small_uint_t) (tv)->us[DUK_DBL_IDX_US0])
635
636#define DUK_TVAL_IS_UNDEFINED(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_UNDEFINED)
637#define DUK_TVAL_IS_UNUSED(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_UNUSED)
638#define DUK_TVAL_IS_NULL(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_NULL)
639#define DUK_TVAL_IS_BOOLEAN(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_BOOLEAN)
640#define DUK_TVAL_IS_BOOLEAN_TRUE(tv) ((tv)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_TRUE)
641#define DUK_TVAL_IS_BOOLEAN_FALSE(tv) ((tv)->ui[DUK_DBL_IDX_UI0] == DUK_XTAG_BOOLEAN_FALSE)
642#define DUK_TVAL_IS_LIGHTFUNC(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_LIGHTFUNC)
643#define DUK_TVAL_IS_STRING(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_STRING)
644#define DUK_TVAL_IS_OBJECT(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_OBJECT)
645#define DUK_TVAL_IS_BUFFER(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_BUFFER)
646#define DUK_TVAL_IS_POINTER(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_POINTER)
647#if defined(DUK_USE_FASTINT)
648/* 0xfff0 is -Infinity */
649#define DUK_TVAL_IS_DOUBLE(tv) (DUK_TVAL_GET_TAG((tv)) <= 0xfff0UL)
650#define DUK_TVAL_IS_FASTINT(tv) (DUK_TVAL_GET_TAG((tv)) == DUK_TAG_FASTINT)
651#define DUK_TVAL_IS_NUMBER(tv) (DUK_TVAL_GET_TAG((tv)) <= 0xfff1UL)
652#else
653#define DUK_TVAL_IS_NUMBER(tv) (DUK_TVAL_GET_TAG((tv)) <= 0xfff0UL)
654#define DUK_TVAL_IS_DOUBLE(tv) DUK_TVAL_IS_NUMBER((tv))
655#endif
656
657/* This is performance critical because it appears in every DECREF. */
658#define DUK_TVAL_IS_HEAP_ALLOCATED(tv) (DUK_TVAL_GET_TAG((tv)) >= DUK_TAG_STRING)
659
660#if defined(DUK_USE_FASTINT)
661DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_packed(duk_tval *tv);
662#endif
663
664#else /* DUK_USE_PACKED_TVAL */
665/* ======================================================================== */
666
667/*
668 * Portable 12-byte representation
669 */
670
671/* Note: not initializing all bytes is normally not an issue: Duktape won't
672 * read or use the uninitialized bytes so valgrind won't issue warnings.
673 * In some special cases a harmless valgrind warning may be issued though.
674 * For example, the DumpHeap debugger command writes out a compiled function's
675 * 'data' area as is, including any uninitialized bytes, which causes a
676 * valgrind warning.
677 */
678
679typedef struct duk_tval_struct duk_tval;
680
682 duk_small_uint_t t;
683 duk_small_uint_t v_extra;
684 union {
685 duk_double_t d;
686 duk_small_int_t i;
687#if defined(DUK_USE_FASTINT)
688 duk_int64_t fi; /* if present, forces 16-byte duk_tval */
689#endif
690 void *voidptr;
691 duk_hstring *hstring;
692 duk_hobject *hobject;
693 duk_hcompfunc *hcompfunc;
694 duk_hnatfunc *hnatfunc;
695 duk_hthread *hthread;
696 duk_hbuffer *hbuffer;
697 duk_heaphdr *heaphdr;
698 duk_c_function lightfunc;
699 } v;
700};
701
702typedef struct {
703 duk_small_uint_t t;
704 duk_small_uint_t v_extra;
705 /* The rest of the fields don't matter except for debug dumps and such
706 * for which a partial initializer may trigger out-ot-bounds memory
707 * reads. Include a double field which is usually as large or larger
708 * than pointers (not always however).
709 */
710 duk_double_t d;
712
713#define DUK_TVAL_UNUSED_INITIALIZER() \
714 { DUK_TAG_UNUSED, 0, 0.0 }
715
716#define DUK_TAG_MIN 0
717#define DUK_TAG_NUMBER 0 /* DUK_TAG_NUMBER only defined for non-packed duk_tval */
718#if defined(DUK_USE_FASTINT)
719#define DUK_TAG_FASTINT 1
720#endif
721#define DUK_TAG_UNDEFINED 2
722#define DUK_TAG_NULL 3
723#define DUK_TAG_BOOLEAN 4
724#define DUK_TAG_POINTER 5
725#define DUK_TAG_LIGHTFUNC 6
726#define DUK_TAG_UNUSED 7 /* marker; not actual tagged type */
727#define DUK_TAG_STRING 8 /* first heap allocated, match bit boundary */
728#define DUK_TAG_OBJECT 9
729#define DUK_TAG_BUFFER 10
730#define DUK_TAG_MAX 10
731
732#define DUK_TVAL_IS_VALID_TAG(tv) \
733 (DUK_TVAL_GET_TAG((tv)) - DUK_TAG_MIN <= DUK_TAG_MAX - DUK_TAG_MIN)
734
735/* DUK_TAG_NUMBER is intentionally first, as it is the default clause in code
736 * to support the 8-byte representation. Further, it is a non-heap-allocated
737 * type so it should come before DUK_TAG_STRING. Finally, it should not break
738 * the tag value ranges covered by case-clauses in a switch-case.
739 */
740
741/* setters */
742#define DUK_TVAL_SET_UNDEFINED(tv) do { \
743 duk_tval *duk__tv; \
744 duk__tv = (tv); \
745 duk__tv->t = DUK_TAG_UNDEFINED; \
746 } while (0)
747
748#define DUK_TVAL_SET_UNUSED(tv) do { \
749 duk_tval *duk__tv; \
750 duk__tv = (tv); \
751 duk__tv->t = DUK_TAG_UNUSED; \
752 } while (0)
753
754#define DUK_TVAL_SET_NULL(tv) do { \
755 duk_tval *duk__tv; \
756 duk__tv = (tv); \
757 duk__tv->t = DUK_TAG_NULL; \
758 } while (0)
759
760#define DUK_TVAL_SET_BOOLEAN(tv,val) do { \
761 duk_tval *duk__tv; \
762 duk__tv = (tv); \
763 duk__tv->t = DUK_TAG_BOOLEAN; \
764 duk__tv->v.i = (val); \
765 } while (0)
766
767#if defined(DUK_USE_FASTINT)
768#define DUK_TVAL_SET_DOUBLE(tv,val) do { \
769 duk_tval *duk__tv; \
770 duk_double_t duk__dblval; \
771 duk__dblval = (val); \
772 DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); /* nop for unpacked duk_tval */ \
773 duk__tv = (tv); \
774 duk__tv->t = DUK_TAG_NUMBER; \
775 duk__tv->v.d = duk__dblval; \
776 } while (0)
777#define DUK_TVAL_SET_I48(tv,val) do { \
778 duk_tval *duk__tv; \
779 duk__tv = (tv); \
780 duk__tv->t = DUK_TAG_FASTINT; \
781 duk__tv->v.fi = (val); \
782 } while (0)
783#define DUK_TVAL_SET_U32(tv,val) do { \
784 duk_tval *duk__tv; \
785 duk__tv = (tv); \
786 duk__tv->t = DUK_TAG_FASTINT; \
787 duk__tv->v.fi = (duk_int64_t) (val); \
788 } while (0)
789#define DUK_TVAL_SET_I32(tv,val) do { \
790 duk_tval *duk__tv; \
791 duk__tv = (tv); \
792 duk__tv->t = DUK_TAG_FASTINT; \
793 duk__tv->v.fi = (duk_int64_t) (val); \
794 } while (0)
795#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) \
796 duk_tval_set_number_chkfast_fast((tv), (d))
797#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) \
798 duk_tval_set_number_chkfast_slow((tv), (d))
799#define DUK_TVAL_SET_NUMBER(tv,val) \
800 DUK_TVAL_SET_DOUBLE((tv), (val))
801#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { \
802 duk_tval *duk__tv; \
803 duk_double_t duk__d; \
804 duk__tv = (tv); \
805 if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
806 duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
807 DUK_TVAL_SET_NUMBER_CHKFAST_FAST(duk__tv, duk__d); \
808 } \
809 } while (0)
810#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { \
811 duk_tval *duk__tv; \
812 duk_double_t duk__d; \
813 duk__tv = (tv); \
814 if (DUK_TVAL_IS_DOUBLE(duk__tv)) { \
815 duk__d = DUK_TVAL_GET_DOUBLE(duk__tv); \
816 DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(duk__tv, duk__d); \
817 } \
818 } while (0)
819#else /* DUK_USE_FASTINT */
820#define DUK_TVAL_SET_DOUBLE(tv,d) \
821 DUK_TVAL_SET_NUMBER((tv), (d))
822#define DUK_TVAL_SET_I48(tv,val) \
823 DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val)) /* XXX: fast int-to-double */
824#define DUK_TVAL_SET_U32(tv,val) \
825 DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val))
826#define DUK_TVAL_SET_I32(tv,val) \
827 DUK_TVAL_SET_NUMBER((tv), (duk_double_t) (val))
828#define DUK_TVAL_SET_NUMBER(tv,val) do { \
829 duk_tval *duk__tv; \
830 duk_double_t duk__dblval; \
831 duk__dblval = (val); \
832 DUK_ASSERT_DOUBLE_IS_NORMALIZED(duk__dblval); /* nop for unpacked duk_tval */ \
833 duk__tv = (tv); \
834 duk__tv->t = DUK_TAG_NUMBER; \
835 duk__tv->v.d = duk__dblval; \
836 } while (0)
837#define DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv,d) \
838 DUK_TVAL_SET_NUMBER((tv), (d))
839#define DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv,d) \
840 DUK_TVAL_SET_NUMBER((tv), (d))
841#define DUK_TVAL_CHKFAST_INPLACE_FAST(tv) do { } while (0)
842#define DUK_TVAL_CHKFAST_INPLACE_SLOW(tv) do { } while (0)
843#endif /* DUK_USE_FASTINT */
844
845#define DUK_TVAL_SET_FASTINT(tv,i) \
846 DUK_TVAL_SET_I48((tv), (i)) /* alias */
847
848#define DUK_TVAL_SET_POINTER(tv,hptr) do { \
849 duk_tval *duk__tv; \
850 duk__tv = (tv); \
851 duk__tv->t = DUK_TAG_POINTER; \
852 duk__tv->v.voidptr = (hptr); \
853 } while (0)
854
855#define DUK_TVAL_SET_LIGHTFUNC(tv,fp,flags) do { \
856 duk_tval *duk__tv; \
857 duk__tv = (tv); \
858 duk__tv->t = DUK_TAG_LIGHTFUNC; \
859 duk__tv->v_extra = (flags); \
860 duk__tv->v.lightfunc = (duk_c_function) (fp); \
861 } while (0)
862
863#define DUK_TVAL_SET_STRING(tv,hptr) do { \
864 duk_tval *duk__tv; \
865 duk__tv = (tv); \
866 duk__tv->t = DUK_TAG_STRING; \
867 duk__tv->v.hstring = (hptr); \
868 } while (0)
869
870#define DUK_TVAL_SET_OBJECT(tv,hptr) do { \
871 duk_tval *duk__tv; \
872 duk__tv = (tv); \
873 duk__tv->t = DUK_TAG_OBJECT; \
874 duk__tv->v.hobject = (hptr); \
875 } while (0)
876
877#define DUK_TVAL_SET_BUFFER(tv,hptr) do { \
878 duk_tval *duk__tv; \
879 duk__tv = (tv); \
880 duk__tv->t = DUK_TAG_BUFFER; \
881 duk__tv->v.hbuffer = (hptr); \
882 } while (0)
883
884#define DUK_TVAL_SET_NAN(tv) do { \
885 /* in non-packed representation we don't care about which NaN is used */ \
886 duk_tval *duk__tv; \
887 duk__tv = (tv); \
888 duk__tv->t = DUK_TAG_NUMBER; \
889 duk__tv->v.d = DUK_DOUBLE_NAN; \
890 } while (0)
891
892#define DUK_TVAL_SET_TVAL(tv,x) do { *(tv) = *(x); } while (0)
893
894/* getters */
895#define DUK_TVAL_GET_BOOLEAN(tv) ((tv)->v.i)
896#if defined(DUK_USE_FASTINT)
897#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->v.d)
898#define DUK_TVAL_GET_FASTINT(tv) ((tv)->v.fi)
899#define DUK_TVAL_GET_FASTINT_U32(tv) ((duk_uint32_t) ((tv)->v.fi))
900#define DUK_TVAL_GET_FASTINT_I32(tv) ((duk_int32_t) ((tv)->v.fi))
901#if 0
902#define DUK_TVAL_GET_NUMBER(tv) (DUK_TVAL_IS_FASTINT((tv)) ? \
903 (duk_double_t) DUK_TVAL_GET_FASTINT((tv)) : \
904 DUK_TVAL_GET_DOUBLE((tv)))
905#define DUK_TVAL_GET_NUMBER(tv) duk_tval_get_number_unpacked((tv))
906#else
907/* This seems reasonable overall. */
908#define DUK_TVAL_GET_NUMBER(tv) (DUK_TVAL_IS_FASTINT((tv)) ? \
909 duk_tval_get_number_unpacked_fastint((tv)) : \
910 DUK_TVAL_GET_DOUBLE((tv)))
911#endif
912#else
913#define DUK_TVAL_GET_NUMBER(tv) ((tv)->v.d)
914#define DUK_TVAL_GET_DOUBLE(tv) ((tv)->v.d)
915#endif /* DUK_USE_FASTINT */
916#define DUK_TVAL_GET_POINTER(tv) ((tv)->v.voidptr)
917#define DUK_TVAL_GET_LIGHTFUNC(tv,out_fp,out_flags) do { \
918 (out_flags) = (duk_uint32_t) (tv)->v_extra; \
919 (out_fp) = (tv)->v.lightfunc; \
920 } while (0)
921#define DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv) ((tv)->v.lightfunc)
922#define DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv) ((duk_uint32_t) ((tv)->v_extra))
923#define DUK_TVAL_GET_STRING(tv) ((tv)->v.hstring)
924#define DUK_TVAL_GET_OBJECT(tv) ((tv)->v.hobject)
925#define DUK_TVAL_GET_BUFFER(tv) ((tv)->v.hbuffer)
926#define DUK_TVAL_GET_HEAPHDR(tv) ((tv)->v.heaphdr)
927
928/* decoding */
929#define DUK_TVAL_GET_TAG(tv) ((tv)->t)
930#define DUK_TVAL_IS_UNDEFINED(tv) ((tv)->t == DUK_TAG_UNDEFINED)
931#define DUK_TVAL_IS_UNUSED(tv) ((tv)->t == DUK_TAG_UNUSED)
932#define DUK_TVAL_IS_NULL(tv) ((tv)->t == DUK_TAG_NULL)
933#define DUK_TVAL_IS_BOOLEAN(tv) ((tv)->t == DUK_TAG_BOOLEAN)
934#define DUK_TVAL_IS_BOOLEAN_TRUE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i != 0))
935#define DUK_TVAL_IS_BOOLEAN_FALSE(tv) (((tv)->t == DUK_TAG_BOOLEAN) && ((tv)->v.i == 0))
936#if defined(DUK_USE_FASTINT)
937#define DUK_TVAL_IS_DOUBLE(tv) ((tv)->t == DUK_TAG_NUMBER)
938#define DUK_TVAL_IS_FASTINT(tv) ((tv)->t == DUK_TAG_FASTINT)
939#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK_TAG_NUMBER || \
940 (tv)->t == DUK_TAG_FASTINT)
941#else
942#define DUK_TVAL_IS_NUMBER(tv) ((tv)->t == DUK_TAG_NUMBER)
943#define DUK_TVAL_IS_DOUBLE(tv) DUK_TVAL_IS_NUMBER((tv))
944#endif /* DUK_USE_FASTINT */
945#define DUK_TVAL_IS_POINTER(tv) ((tv)->t == DUK_TAG_POINTER)
946#define DUK_TVAL_IS_LIGHTFUNC(tv) ((tv)->t == DUK_TAG_LIGHTFUNC)
947#define DUK_TVAL_IS_STRING(tv) ((tv)->t == DUK_TAG_STRING)
948#define DUK_TVAL_IS_OBJECT(tv) ((tv)->t == DUK_TAG_OBJECT)
949#define DUK_TVAL_IS_BUFFER(tv) ((tv)->t == DUK_TAG_BUFFER)
950
951/* This is performance critical because it's needed for every DECREF.
952 * Take advantage of the fact that the first heap allocated tag is 8,
953 * so that bit 3 is set for all heap allocated tags (and never set for
954 * non-heap-allocated tags).
955 */
956#if 0
957#define DUK_TVAL_IS_HEAP_ALLOCATED(tv) ((tv)->t >= DUK_TAG_STRING)
958#endif
959#define DUK_TVAL_IS_HEAP_ALLOCATED(tv) ((tv)->t & 0x08)
960
961#if defined(DUK_USE_FASTINT)
962#if 0
963DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked(duk_tval *tv);
964#endif
965DUK_INTERNAL_DECL duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv);
966#endif
967
968#endif /* DUK_USE_PACKED_TVAL */
969
970/*
971 * Convenience (independent of representation)
972 */
973
974#define DUK_TVAL_SET_BOOLEAN_TRUE(tv) DUK_TVAL_SET_BOOLEAN((tv), 1)
975#define DUK_TVAL_SET_BOOLEAN_FALSE(tv) DUK_TVAL_SET_BOOLEAN((tv), 0)
976
977#define DUK_TVAL_STRING_IS_SYMBOL(tv) \
978 DUK_HSTRING_HAS_SYMBOL(DUK_TVAL_GET_STRING((tv)))
979
980/* Lightfunc flags packing and unpacking. */
981/* Sign extend: 0x0000##00 -> 0x##000000 -> sign extend to 0xssssss##.
982 * Avoid signed shifts due to portability limitations.
983 */
984#define DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags) \
985 ((duk_int32_t) (duk_int8_t) (((duk_uint16_t) (lf_flags)) >> 8))
986#define DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags) \
987 (((lf_flags) >> 4) & 0x0f)
988#define DUK_LFUNC_FLAGS_GET_NARGS(lf_flags) \
989 ((lf_flags) & 0x0f)
990#define DUK_LFUNC_FLAGS_PACK(magic,length,nargs) \
991 (((magic) & 0xff) << 8) | ((length) << 4) | (nargs)
992
993#define DUK_LFUNC_NARGS_VARARGS 0x0f /* varargs marker */
994#define DUK_LFUNC_NARGS_MIN 0x00
995#define DUK_LFUNC_NARGS_MAX 0x0e /* max, excl. varargs marker */
996#define DUK_LFUNC_LENGTH_MIN 0x00
997#define DUK_LFUNC_LENGTH_MAX 0x0f
998#define DUK_LFUNC_MAGIC_MIN (-0x80)
999#define DUK_LFUNC_MAGIC_MAX 0x7f
1000
1001/* fastint constants etc */
1002#if defined(DUK_USE_FASTINT)
1003#define DUK_FASTINT_MIN (-0x800000000000LL)
1004#define DUK_FASTINT_MAX 0x7fffffffffffLL
1005#define DUK_FASTINT_BITS 48
1006
1007DUK_INTERNAL_DECL void duk_tval_set_number_chkfast_fast(duk_tval *tv, duk_double_t x);
1008DUK_INTERNAL_DECL void duk_tval_set_number_chkfast_slow(duk_tval *tv, duk_double_t x);
1009#endif
1010
1011#endif /* DUK_TVAL_H_INCLUDED */
1012/* #include duk_builtins.h */
1013/*
1014 * Automatically generated by genbuiltins.py, do not edit!
1015 */
1016
1017#if !defined(DUK_BUILTINS_H_INCLUDED)
1018#define DUK_BUILTINS_H_INCLUDED
1019
1020#if defined(DUK_USE_ROM_STRINGS)
1021#error ROM support not enabled, rerun configure.py with --rom-support
1022#else /* DUK_USE_ROM_STRINGS */
1023#define DUK_STRIDX_UC_UNDEFINED 0 /* 'Undefined' */
1024#define DUK_HEAP_STRING_UC_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_UNDEFINED)
1025#define DUK_HTHREAD_STRING_UC_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_UNDEFINED)
1026#define DUK_STRIDX_UC_NULL 1 /* 'Null' */
1027#define DUK_HEAP_STRING_UC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NULL)
1028#define DUK_HTHREAD_STRING_UC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NULL)
1029#define DUK_STRIDX_UC_SYMBOL 2 /* 'Symbol' */
1030#define DUK_HEAP_STRING_UC_SYMBOL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_SYMBOL)
1031#define DUK_HTHREAD_STRING_UC_SYMBOL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_SYMBOL)
1032#define DUK_STRIDX_UC_ARGUMENTS 3 /* 'Arguments' */
1033#define DUK_HEAP_STRING_UC_ARGUMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ARGUMENTS)
1034#define DUK_HTHREAD_STRING_UC_ARGUMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ARGUMENTS)
1035#define DUK_STRIDX_UC_OBJECT 4 /* 'Object' */
1036#define DUK_HEAP_STRING_UC_OBJECT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_OBJECT)
1037#define DUK_HTHREAD_STRING_UC_OBJECT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_OBJECT)
1038#define DUK_STRIDX_UC_FUNCTION 5 /* 'Function' */
1039#define DUK_HEAP_STRING_UC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_FUNCTION)
1040#define DUK_HTHREAD_STRING_UC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_FUNCTION)
1041#define DUK_STRIDX_ARRAY 6 /* 'Array' */
1042#define DUK_HEAP_STRING_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ARRAY)
1043#define DUK_HTHREAD_STRING_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ARRAY)
1044#define DUK_STRIDX_UC_STRING 7 /* 'String' */
1045#define DUK_HEAP_STRING_UC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_STRING)
1046#define DUK_HTHREAD_STRING_UC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_STRING)
1047#define DUK_STRIDX_UC_BOOLEAN 8 /* 'Boolean' */
1048#define DUK_HEAP_STRING_UC_BOOLEAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BOOLEAN)
1049#define DUK_HTHREAD_STRING_UC_BOOLEAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BOOLEAN)
1050#define DUK_STRIDX_UC_NUMBER 9 /* 'Number' */
1051#define DUK_HEAP_STRING_UC_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_NUMBER)
1052#define DUK_HTHREAD_STRING_UC_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_NUMBER)
1053#define DUK_STRIDX_DATE 10 /* 'Date' */
1054#define DUK_HEAP_STRING_DATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATE)
1055#define DUK_HTHREAD_STRING_DATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATE)
1056#define DUK_STRIDX_REG_EXP 11 /* 'RegExp' */
1057#define DUK_HEAP_STRING_REG_EXP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_REG_EXP)
1058#define DUK_HTHREAD_STRING_REG_EXP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_REG_EXP)
1059#define DUK_STRIDX_UC_ERROR 12 /* 'Error' */
1060#define DUK_HEAP_STRING_UC_ERROR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_ERROR)
1061#define DUK_HTHREAD_STRING_UC_ERROR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_ERROR)
1062#define DUK_STRIDX_MATH 13 /* 'Math' */
1063#define DUK_HEAP_STRING_MATH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MATH)
1064#define DUK_HTHREAD_STRING_MATH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MATH)
1065#define DUK_STRIDX_JSON 14 /* 'JSON' */
1066#define DUK_HEAP_STRING_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON)
1067#define DUK_HTHREAD_STRING_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON)
1068#define DUK_STRIDX_EMPTY_STRING 15 /* '' */
1069#define DUK_HEAP_STRING_EMPTY_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EMPTY_STRING)
1070#define DUK_HTHREAD_STRING_EMPTY_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EMPTY_STRING)
1071#define DUK_STRIDX_ARRAY_BUFFER 16 /* 'ArrayBuffer' */
1072#define DUK_HEAP_STRING_ARRAY_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ARRAY_BUFFER)
1073#define DUK_HTHREAD_STRING_ARRAY_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ARRAY_BUFFER)
1074#define DUK_STRIDX_DATA_VIEW 17 /* 'DataView' */
1075#define DUK_HEAP_STRING_DATA_VIEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA_VIEW)
1076#define DUK_HTHREAD_STRING_DATA_VIEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA_VIEW)
1077#define DUK_STRIDX_INT8_ARRAY 18 /* 'Int8Array' */
1078#define DUK_HEAP_STRING_INT8_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT8_ARRAY)
1079#define DUK_HTHREAD_STRING_INT8_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT8_ARRAY)
1080#define DUK_STRIDX_UINT8_ARRAY 19 /* 'Uint8Array' */
1081#define DUK_HEAP_STRING_UINT8_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_ARRAY)
1082#define DUK_HTHREAD_STRING_UINT8_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_ARRAY)
1083#define DUK_STRIDX_UINT8_CLAMPED_ARRAY 20 /* 'Uint8ClampedArray' */
1084#define DUK_HEAP_STRING_UINT8_CLAMPED_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT8_CLAMPED_ARRAY)
1085#define DUK_HTHREAD_STRING_UINT8_CLAMPED_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT8_CLAMPED_ARRAY)
1086#define DUK_STRIDX_INT16_ARRAY 21 /* 'Int16Array' */
1087#define DUK_HEAP_STRING_INT16_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT16_ARRAY)
1088#define DUK_HTHREAD_STRING_INT16_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT16_ARRAY)
1089#define DUK_STRIDX_UINT16_ARRAY 22 /* 'Uint16Array' */
1090#define DUK_HEAP_STRING_UINT16_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT16_ARRAY)
1091#define DUK_HTHREAD_STRING_UINT16_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT16_ARRAY)
1092#define DUK_STRIDX_INT32_ARRAY 23 /* 'Int32Array' */
1093#define DUK_HEAP_STRING_INT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT32_ARRAY)
1094#define DUK_HTHREAD_STRING_INT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT32_ARRAY)
1095#define DUK_STRIDX_UINT32_ARRAY 24 /* 'Uint32Array' */
1096#define DUK_HEAP_STRING_UINT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UINT32_ARRAY)
1097#define DUK_HTHREAD_STRING_UINT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UINT32_ARRAY)
1098#define DUK_STRIDX_FLOAT32_ARRAY 25 /* 'Float32Array' */
1099#define DUK_HEAP_STRING_FLOAT32_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT32_ARRAY)
1100#define DUK_HTHREAD_STRING_FLOAT32_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT32_ARRAY)
1101#define DUK_STRIDX_FLOAT64_ARRAY 26 /* 'Float64Array' */
1102#define DUK_HEAP_STRING_FLOAT64_ARRAY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLOAT64_ARRAY)
1103#define DUK_HTHREAD_STRING_FLOAT64_ARRAY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLOAT64_ARRAY)
1104#define DUK_STRIDX_GLOBAL 27 /* 'global' */
1105#define DUK_HEAP_STRING_GLOBAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GLOBAL)
1106#define DUK_HTHREAD_STRING_GLOBAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GLOBAL)
1107#define DUK_STRIDX_OBJ_ENV 28 /* 'ObjEnv' */
1108#define DUK_HEAP_STRING_OBJ_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OBJ_ENV)
1109#define DUK_HTHREAD_STRING_OBJ_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OBJ_ENV)
1110#define DUK_STRIDX_DEC_ENV 29 /* 'DecEnv' */
1111#define DUK_HEAP_STRING_DEC_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEC_ENV)
1112#define DUK_HTHREAD_STRING_DEC_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEC_ENV)
1113#define DUK_STRIDX_UC_BUFFER 30 /* 'Buffer' */
1114#define DUK_HEAP_STRING_UC_BUFFER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_BUFFER)
1115#define DUK_HTHREAD_STRING_UC_BUFFER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_BUFFER)
1116#define DUK_STRIDX_UC_POINTER 31 /* 'Pointer' */
1117#define DUK_HEAP_STRING_UC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_POINTER)
1118#define DUK_HTHREAD_STRING_UC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_POINTER)
1119#define DUK_STRIDX_UC_THREAD 32 /* 'Thread' */
1120#define DUK_HEAP_STRING_UC_THREAD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_UC_THREAD)
1121#define DUK_HTHREAD_STRING_UC_THREAD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_UC_THREAD)
1122#define DUK_STRIDX_EVAL 33 /* 'eval' */
1123#define DUK_HEAP_STRING_EVAL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EVAL)
1124#define DUK_HTHREAD_STRING_EVAL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EVAL)
1125#define DUK_STRIDX_VALUE 34 /* 'value' */
1126#define DUK_HEAP_STRING_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE)
1127#define DUK_HTHREAD_STRING_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE)
1128#define DUK_STRIDX_WRITABLE 35 /* 'writable' */
1129#define DUK_HEAP_STRING_WRITABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WRITABLE)
1130#define DUK_HTHREAD_STRING_WRITABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WRITABLE)
1131#define DUK_STRIDX_CONFIGURABLE 36 /* 'configurable' */
1132#define DUK_HEAP_STRING_CONFIGURABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONFIGURABLE)
1133#define DUK_HTHREAD_STRING_CONFIGURABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONFIGURABLE)
1134#define DUK_STRIDX_ENUMERABLE 37 /* 'enumerable' */
1135#define DUK_HEAP_STRING_ENUMERABLE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUMERABLE)
1136#define DUK_HTHREAD_STRING_ENUMERABLE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUMERABLE)
1137#define DUK_STRIDX_JOIN 38 /* 'join' */
1138#define DUK_HEAP_STRING_JOIN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JOIN)
1139#define DUK_HTHREAD_STRING_JOIN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JOIN)
1140#define DUK_STRIDX_TO_LOCALE_STRING 39 /* 'toLocaleString' */
1141#define DUK_HEAP_STRING_TO_LOCALE_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_LOCALE_STRING)
1142#define DUK_HTHREAD_STRING_TO_LOCALE_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_LOCALE_STRING)
1143#define DUK_STRIDX_VALUE_OF 40 /* 'valueOf' */
1144#define DUK_HEAP_STRING_VALUE_OF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VALUE_OF)
1145#define DUK_HTHREAD_STRING_VALUE_OF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VALUE_OF)
1146#define DUK_STRIDX_TO_UTC_STRING 41 /* 'toUTCString' */
1147#define DUK_HEAP_STRING_TO_UTC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_UTC_STRING)
1148#define DUK_HTHREAD_STRING_TO_UTC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_UTC_STRING)
1149#define DUK_STRIDX_TO_ISO_STRING 42 /* 'toISOString' */
1150#define DUK_HEAP_STRING_TO_ISO_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_ISO_STRING)
1151#define DUK_HTHREAD_STRING_TO_ISO_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_ISO_STRING)
1152#define DUK_STRIDX_TO_GMT_STRING 43 /* 'toGMTString' */
1153#define DUK_HEAP_STRING_TO_GMT_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_GMT_STRING)
1154#define DUK_HTHREAD_STRING_TO_GMT_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_GMT_STRING)
1155#define DUK_STRIDX_SOURCE 44 /* 'source' */
1156#define DUK_HEAP_STRING_SOURCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SOURCE)
1157#define DUK_HTHREAD_STRING_SOURCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SOURCE)
1158#define DUK_STRIDX_IGNORE_CASE 45 /* 'ignoreCase' */
1159#define DUK_HEAP_STRING_IGNORE_CASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IGNORE_CASE)
1160#define DUK_HTHREAD_STRING_IGNORE_CASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IGNORE_CASE)
1161#define DUK_STRIDX_MULTILINE 46 /* 'multiline' */
1162#define DUK_HEAP_STRING_MULTILINE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MULTILINE)
1163#define DUK_HTHREAD_STRING_MULTILINE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MULTILINE)
1164#define DUK_STRIDX_LAST_INDEX 47 /* 'lastIndex' */
1165#define DUK_HEAP_STRING_LAST_INDEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LAST_INDEX)
1166#define DUK_HTHREAD_STRING_LAST_INDEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LAST_INDEX)
1167#define DUK_STRIDX_FLAGS 48 /* 'flags' */
1168#define DUK_HEAP_STRING_FLAGS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FLAGS)
1169#define DUK_HTHREAD_STRING_FLAGS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FLAGS)
1170#define DUK_STRIDX_INDEX 49 /* 'index' */
1171#define DUK_HEAP_STRING_INDEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INDEX)
1172#define DUK_HTHREAD_STRING_INDEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INDEX)
1173#define DUK_STRIDX_PROTOTYPE 50 /* 'prototype' */
1174#define DUK_HEAP_STRING_PROTOTYPE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTOTYPE)
1175#define DUK_HTHREAD_STRING_PROTOTYPE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTOTYPE)
1176#define DUK_STRIDX_CONSTRUCTOR 51 /* 'constructor' */
1177#define DUK_HEAP_STRING_CONSTRUCTOR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONSTRUCTOR)
1178#define DUK_HTHREAD_STRING_CONSTRUCTOR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONSTRUCTOR)
1179#define DUK_STRIDX_MESSAGE 52 /* 'message' */
1180#define DUK_HEAP_STRING_MESSAGE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MESSAGE)
1181#define DUK_HTHREAD_STRING_MESSAGE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MESSAGE)
1182#define DUK_STRIDX_LC_BOOLEAN 53 /* 'boolean' */
1183#define DUK_HEAP_STRING_LC_BOOLEAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_BOOLEAN)
1184#define DUK_HTHREAD_STRING_LC_BOOLEAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_BOOLEAN)
1185#define DUK_STRIDX_LC_NUMBER 54 /* 'number' */
1186#define DUK_HEAP_STRING_LC_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NUMBER)
1187#define DUK_HTHREAD_STRING_LC_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NUMBER)
1188#define DUK_STRIDX_LC_STRING 55 /* 'string' */
1189#define DUK_HEAP_STRING_LC_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_STRING)
1190#define DUK_HTHREAD_STRING_LC_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_STRING)
1191#define DUK_STRIDX_LC_SYMBOL 56 /* 'symbol' */
1192#define DUK_HEAP_STRING_LC_SYMBOL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_SYMBOL)
1193#define DUK_HTHREAD_STRING_LC_SYMBOL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_SYMBOL)
1194#define DUK_STRIDX_LC_OBJECT 57 /* 'object' */
1195#define DUK_HEAP_STRING_LC_OBJECT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_OBJECT)
1196#define DUK_HTHREAD_STRING_LC_OBJECT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_OBJECT)
1197#define DUK_STRIDX_LC_UNDEFINED 58 /* 'undefined' */
1198#define DUK_HEAP_STRING_LC_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_UNDEFINED)
1199#define DUK_HTHREAD_STRING_LC_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_UNDEFINED)
1200#define DUK_STRIDX_NAN 59 /* 'NaN' */
1201#define DUK_HEAP_STRING_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAN)
1202#define DUK_HTHREAD_STRING_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAN)
1203#define DUK_STRIDX_INFINITY 60 /* 'Infinity' */
1204#define DUK_HEAP_STRING_INFINITY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INFINITY)
1205#define DUK_HTHREAD_STRING_INFINITY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INFINITY)
1206#define DUK_STRIDX_MINUS_INFINITY 61 /* '-Infinity' */
1207#define DUK_HEAP_STRING_MINUS_INFINITY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_INFINITY)
1208#define DUK_HTHREAD_STRING_MINUS_INFINITY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_INFINITY)
1209#define DUK_STRIDX_MINUS_ZERO 62 /* '-0' */
1210#define DUK_HEAP_STRING_MINUS_ZERO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_MINUS_ZERO)
1211#define DUK_HTHREAD_STRING_MINUS_ZERO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_MINUS_ZERO)
1212#define DUK_STRIDX_COMMA 63 /* ',' */
1213#define DUK_HEAP_STRING_COMMA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMMA)
1214#define DUK_HTHREAD_STRING_COMMA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMMA)
1215#define DUK_STRIDX_NEWLINE_4SPACE 64 /* '\n ' */
1216#define DUK_HEAP_STRING_NEWLINE_4SPACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEWLINE_4SPACE)
1217#define DUK_HTHREAD_STRING_NEWLINE_4SPACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEWLINE_4SPACE)
1218#define DUK_STRIDX_BRACKETED_ELLIPSIS 65 /* '[...]' */
1219#define DUK_HEAP_STRING_BRACKETED_ELLIPSIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BRACKETED_ELLIPSIS)
1220#define DUK_HTHREAD_STRING_BRACKETED_ELLIPSIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BRACKETED_ELLIPSIS)
1221#define DUK_STRIDX_INVALID_DATE 66 /* 'Invalid Date' */
1222#define DUK_HEAP_STRING_INVALID_DATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INVALID_DATE)
1223#define DUK_HTHREAD_STRING_INVALID_DATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INVALID_DATE)
1224#define DUK_STRIDX_LC_ARGUMENTS 67 /* 'arguments' */
1225#define DUK_HEAP_STRING_LC_ARGUMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_ARGUMENTS)
1226#define DUK_HTHREAD_STRING_LC_ARGUMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_ARGUMENTS)
1227#define DUK_STRIDX_CALLEE 68 /* 'callee' */
1228#define DUK_HEAP_STRING_CALLEE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLEE)
1229#define DUK_HTHREAD_STRING_CALLEE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLEE)
1230#define DUK_STRIDX_CALLER 69 /* 'caller' */
1231#define DUK_HEAP_STRING_CALLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CALLER)
1232#define DUK_HTHREAD_STRING_CALLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CALLER)
1233#define DUK_STRIDX_DELETE_PROPERTY 70 /* 'deleteProperty' */
1234#define DUK_HEAP_STRING_DELETE_PROPERTY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE_PROPERTY)
1235#define DUK_HTHREAD_STRING_DELETE_PROPERTY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE_PROPERTY)
1236#define DUK_STRIDX_GET 71 /* 'get' */
1237#define DUK_HEAP_STRING_GET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_GET)
1238#define DUK_HTHREAD_STRING_GET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_GET)
1239#define DUK_STRIDX_HAS 72 /* 'has' */
1240#define DUK_HEAP_STRING_HAS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HAS)
1241#define DUK_HTHREAD_STRING_HAS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HAS)
1242#define DUK_STRIDX_OWN_KEYS 73 /* 'ownKeys' */
1243#define DUK_HEAP_STRING_OWN_KEYS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_OWN_KEYS)
1244#define DUK_HTHREAD_STRING_OWN_KEYS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_OWN_KEYS)
1245#define DUK_STRIDX_SET_PROTOTYPE_OF 74 /* 'setPrototypeOf' */
1246#define DUK_HEAP_STRING_SET_PROTOTYPE_OF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET_PROTOTYPE_OF)
1247#define DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET_PROTOTYPE_OF)
1248#define DUK_STRIDX___PROTO__ 75 /* '__proto__' */
1249#define DUK_HEAP_STRING___PROTO__(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX___PROTO__)
1250#define DUK_HTHREAD_STRING___PROTO__(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX___PROTO__)
1251#define DUK_STRIDX_TO_STRING 76 /* 'toString' */
1252#define DUK_HEAP_STRING_TO_STRING(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_STRING)
1253#define DUK_HTHREAD_STRING_TO_STRING(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_STRING)
1254#define DUK_STRIDX_TO_JSON 77 /* 'toJSON' */
1255#define DUK_HEAP_STRING_TO_JSON(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TO_JSON)
1256#define DUK_HTHREAD_STRING_TO_JSON(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TO_JSON)
1257#define DUK_STRIDX_TYPE 78 /* 'type' */
1258#define DUK_HEAP_STRING_TYPE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPE)
1259#define DUK_HTHREAD_STRING_TYPE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPE)
1260#define DUK_STRIDX_DATA 79 /* 'data' */
1261#define DUK_HEAP_STRING_DATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DATA)
1262#define DUK_HTHREAD_STRING_DATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DATA)
1263#define DUK_STRIDX_LENGTH 80 /* 'length' */
1264#define DUK_HEAP_STRING_LENGTH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LENGTH)
1265#define DUK_HTHREAD_STRING_LENGTH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LENGTH)
1266#define DUK_STRIDX_SET 81 /* 'set' */
1267#define DUK_HEAP_STRING_SET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SET)
1268#define DUK_HTHREAD_STRING_SET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SET)
1269#define DUK_STRIDX_STACK 82 /* 'stack' */
1270#define DUK_HEAP_STRING_STACK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STACK)
1271#define DUK_HTHREAD_STRING_STACK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STACK)
1272#define DUK_STRIDX_PC 83 /* 'pc' */
1273#define DUK_HEAP_STRING_PC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PC)
1274#define DUK_HTHREAD_STRING_PC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PC)
1275#define DUK_STRIDX_LINE_NUMBER 84 /* 'lineNumber' */
1276#define DUK_HEAP_STRING_LINE_NUMBER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LINE_NUMBER)
1277#define DUK_HTHREAD_STRING_LINE_NUMBER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LINE_NUMBER)
1278#define DUK_STRIDX_INT_TRACEDATA 85 /* '\xffTracedata' */
1279#define DUK_HEAP_STRING_INT_TRACEDATA(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TRACEDATA)
1280#define DUK_HTHREAD_STRING_INT_TRACEDATA(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TRACEDATA)
1281#define DUK_STRIDX_NAME 86 /* 'name' */
1282#define DUK_HEAP_STRING_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NAME)
1283#define DUK_HTHREAD_STRING_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NAME)
1284#define DUK_STRIDX_FILE_NAME 87 /* 'fileName' */
1285#define DUK_HEAP_STRING_FILE_NAME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FILE_NAME)
1286#define DUK_HTHREAD_STRING_FILE_NAME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FILE_NAME)
1287#define DUK_STRIDX_LC_POINTER 88 /* 'pointer' */
1288#define DUK_HEAP_STRING_LC_POINTER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_POINTER)
1289#define DUK_HTHREAD_STRING_LC_POINTER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_POINTER)
1290#define DUK_STRIDX_INT_VALUE 89 /* '\xffValue' */
1291#define DUK_HEAP_STRING_INT_VALUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VALUE)
1292#define DUK_HTHREAD_STRING_INT_VALUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VALUE)
1293#define DUK_STRIDX_INT_NEXT 90 /* '\xffNext' */
1294#define DUK_HEAP_STRING_INT_NEXT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_NEXT)
1295#define DUK_HTHREAD_STRING_INT_NEXT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_NEXT)
1296#define DUK_STRIDX_INT_BYTECODE 91 /* '\xffBytecode' */
1297#define DUK_HEAP_STRING_INT_BYTECODE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_BYTECODE)
1298#define DUK_HTHREAD_STRING_INT_BYTECODE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_BYTECODE)
1299#define DUK_STRIDX_INT_FORMALS 92 /* '\xffFormals' */
1300#define DUK_HEAP_STRING_INT_FORMALS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FORMALS)
1301#define DUK_HTHREAD_STRING_INT_FORMALS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FORMALS)
1302#define DUK_STRIDX_INT_VARMAP 93 /* '\xffVarmap' */
1303#define DUK_HEAP_STRING_INT_VARMAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARMAP)
1304#define DUK_HTHREAD_STRING_INT_VARMAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARMAP)
1305#define DUK_STRIDX_INT_SOURCE 94 /* '\xffSource' */
1306#define DUK_HEAP_STRING_INT_SOURCE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_SOURCE)
1307#define DUK_HTHREAD_STRING_INT_SOURCE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_SOURCE)
1308#define DUK_STRIDX_INT_PC2LINE 95 /* '\xffPc2line' */
1309#define DUK_HEAP_STRING_INT_PC2LINE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_PC2LINE)
1310#define DUK_HTHREAD_STRING_INT_PC2LINE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_PC2LINE)
1311#define DUK_STRIDX_INT_ARGS 96 /* '\xffArgs' */
1312#define DUK_HEAP_STRING_INT_ARGS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_ARGS)
1313#define DUK_HTHREAD_STRING_INT_ARGS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_ARGS)
1314#define DUK_STRIDX_INT_MAP 97 /* '\xffMap' */
1315#define DUK_HEAP_STRING_INT_MAP(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_MAP)
1316#define DUK_HTHREAD_STRING_INT_MAP(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_MAP)
1317#define DUK_STRIDX_INT_VARENV 98 /* '\xffVarenv' */
1318#define DUK_HEAP_STRING_INT_VARENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_VARENV)
1319#define DUK_HTHREAD_STRING_INT_VARENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_VARENV)
1320#define DUK_STRIDX_INT_FINALIZER 99 /* '\xffFinalizer' */
1321#define DUK_HEAP_STRING_INT_FINALIZER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_FINALIZER)
1322#define DUK_HTHREAD_STRING_INT_FINALIZER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_FINALIZER)
1323#define DUK_STRIDX_INT_HANDLER 100 /* '\xffHandler' */
1324#define DUK_HEAP_STRING_INT_HANDLER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_HANDLER)
1325#define DUK_HTHREAD_STRING_INT_HANDLER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_HANDLER)
1326#define DUK_STRIDX_INT_CALLEE 101 /* '\xffCallee' */
1327#define DUK_HEAP_STRING_INT_CALLEE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_CALLEE)
1328#define DUK_HTHREAD_STRING_INT_CALLEE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_CALLEE)
1329#define DUK_STRIDX_INT_THREAD 102 /* '\xffThread' */
1330#define DUK_HEAP_STRING_INT_THREAD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THREAD)
1331#define DUK_HTHREAD_STRING_INT_THREAD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THREAD)
1332#define DUK_STRIDX_INT_REGBASE 103 /* '\xffRegbase' */
1333#define DUK_HEAP_STRING_INT_REGBASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_REGBASE)
1334#define DUK_HTHREAD_STRING_INT_REGBASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_REGBASE)
1335#define DUK_STRIDX_INT_TARGET 104 /* '\xffTarget' */
1336#define DUK_HEAP_STRING_INT_TARGET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_TARGET)
1337#define DUK_HTHREAD_STRING_INT_TARGET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_TARGET)
1338#define DUK_STRIDX_INT_THIS 105 /* '\xffThis' */
1339#define DUK_HEAP_STRING_INT_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INT_THIS)
1340#define DUK_HTHREAD_STRING_INT_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INT_THIS)
1341#define DUK_STRIDX_COMPILE 106 /* 'compile' */
1342#define DUK_HEAP_STRING_COMPILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_COMPILE)
1343#define DUK_HTHREAD_STRING_COMPILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_COMPILE)
1344#define DUK_STRIDX_INPUT 107 /* 'input' */
1345#define DUK_HEAP_STRING_INPUT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INPUT)
1346#define DUK_HTHREAD_STRING_INPUT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INPUT)
1347#define DUK_STRIDX_ERR_CREATE 108 /* 'errCreate' */
1348#define DUK_HEAP_STRING_ERR_CREATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_CREATE)
1349#define DUK_HTHREAD_STRING_ERR_CREATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_CREATE)
1350#define DUK_STRIDX_ERR_THROW 109 /* 'errThrow' */
1351#define DUK_HEAP_STRING_ERR_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ERR_THROW)
1352#define DUK_HTHREAD_STRING_ERR_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ERR_THROW)
1353#define DUK_STRIDX_ENV 110 /* 'env' */
1354#define DUK_HEAP_STRING_ENV(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENV)
1355#define DUK_HTHREAD_STRING_ENV(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENV)
1356#define DUK_STRIDX_HEX 111 /* 'hex' */
1357#define DUK_HEAP_STRING_HEX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_HEX)
1358#define DUK_HTHREAD_STRING_HEX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_HEX)
1359#define DUK_STRIDX_BASE64 112 /* 'base64' */
1360#define DUK_HEAP_STRING_BASE64(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BASE64)
1361#define DUK_HTHREAD_STRING_BASE64(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BASE64)
1362#define DUK_STRIDX_JX 113 /* 'jx' */
1363#define DUK_HEAP_STRING_JX(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JX)
1364#define DUK_HTHREAD_STRING_JX(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JX)
1365#define DUK_STRIDX_JC 114 /* 'jc' */
1366#define DUK_HEAP_STRING_JC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JC)
1367#define DUK_HTHREAD_STRING_JC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JC)
1368#define DUK_STRIDX_RESUME 115 /* 'resume' */
1369#define DUK_HEAP_STRING_RESUME(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RESUME)
1370#define DUK_HTHREAD_STRING_RESUME(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RESUME)
1371#define DUK_STRIDX_JSON_EXT_UNDEFINED 116 /* '{"_undef":true}' */
1372#define DUK_HEAP_STRING_JSON_EXT_UNDEFINED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_UNDEFINED)
1373#define DUK_HTHREAD_STRING_JSON_EXT_UNDEFINED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_UNDEFINED)
1374#define DUK_STRIDX_JSON_EXT_NAN 117 /* '{"_nan":true}' */
1375#define DUK_HEAP_STRING_JSON_EXT_NAN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NAN)
1376#define DUK_HTHREAD_STRING_JSON_EXT_NAN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NAN)
1377#define DUK_STRIDX_JSON_EXT_POSINF 118 /* '{"_inf":true}' */
1378#define DUK_HEAP_STRING_JSON_EXT_POSINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_POSINF)
1379#define DUK_HTHREAD_STRING_JSON_EXT_POSINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_POSINF)
1380#define DUK_STRIDX_JSON_EXT_NEGINF 119 /* '{"_ninf":true}' */
1381#define DUK_HEAP_STRING_JSON_EXT_NEGINF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_NEGINF)
1382#define DUK_HTHREAD_STRING_JSON_EXT_NEGINF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_NEGINF)
1383#define DUK_STRIDX_JSON_EXT_FUNCTION1 120 /* '{"_func":true}' */
1384#define DUK_HEAP_STRING_JSON_EXT_FUNCTION1(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION1)
1385#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION1(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION1)
1386#define DUK_STRIDX_JSON_EXT_FUNCTION2 121 /* '{_func:true}' */
1387#define DUK_HEAP_STRING_JSON_EXT_FUNCTION2(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_JSON_EXT_FUNCTION2)
1388#define DUK_HTHREAD_STRING_JSON_EXT_FUNCTION2(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_JSON_EXT_FUNCTION2)
1389#define DUK_STRIDX_BREAK 122 /* 'break' */
1390#define DUK_HEAP_STRING_BREAK(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_BREAK)
1391#define DUK_HTHREAD_STRING_BREAK(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_BREAK)
1392#define DUK_STRIDX_CASE 123 /* 'case' */
1393#define DUK_HEAP_STRING_CASE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CASE)
1394#define DUK_HTHREAD_STRING_CASE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CASE)
1395#define DUK_STRIDX_CATCH 124 /* 'catch' */
1396#define DUK_HEAP_STRING_CATCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CATCH)
1397#define DUK_HTHREAD_STRING_CATCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CATCH)
1398#define DUK_STRIDX_CONTINUE 125 /* 'continue' */
1399#define DUK_HEAP_STRING_CONTINUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONTINUE)
1400#define DUK_HTHREAD_STRING_CONTINUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONTINUE)
1401#define DUK_STRIDX_DEBUGGER 126 /* 'debugger' */
1402#define DUK_HEAP_STRING_DEBUGGER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEBUGGER)
1403#define DUK_HTHREAD_STRING_DEBUGGER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEBUGGER)
1404#define DUK_STRIDX_DEFAULT 127 /* 'default' */
1405#define DUK_HEAP_STRING_DEFAULT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DEFAULT)
1406#define DUK_HTHREAD_STRING_DEFAULT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DEFAULT)
1407#define DUK_STRIDX_DELETE 128 /* 'delete' */
1408#define DUK_HEAP_STRING_DELETE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DELETE)
1409#define DUK_HTHREAD_STRING_DELETE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DELETE)
1410#define DUK_STRIDX_DO 129 /* 'do' */
1411#define DUK_HEAP_STRING_DO(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_DO)
1412#define DUK_HTHREAD_STRING_DO(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_DO)
1413#define DUK_STRIDX_ELSE 130 /* 'else' */
1414#define DUK_HEAP_STRING_ELSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ELSE)
1415#define DUK_HTHREAD_STRING_ELSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ELSE)
1416#define DUK_STRIDX_FINALLY 131 /* 'finally' */
1417#define DUK_HEAP_STRING_FINALLY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FINALLY)
1418#define DUK_HTHREAD_STRING_FINALLY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FINALLY)
1419#define DUK_STRIDX_FOR 132 /* 'for' */
1420#define DUK_HEAP_STRING_FOR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FOR)
1421#define DUK_HTHREAD_STRING_FOR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FOR)
1422#define DUK_STRIDX_LC_FUNCTION 133 /* 'function' */
1423#define DUK_HEAP_STRING_LC_FUNCTION(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_FUNCTION)
1424#define DUK_HTHREAD_STRING_LC_FUNCTION(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_FUNCTION)
1425#define DUK_STRIDX_IF 134 /* 'if' */
1426#define DUK_HEAP_STRING_IF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IF)
1427#define DUK_HTHREAD_STRING_IF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IF)
1428#define DUK_STRIDX_IN 135 /* 'in' */
1429#define DUK_HEAP_STRING_IN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IN)
1430#define DUK_HTHREAD_STRING_IN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IN)
1431#define DUK_STRIDX_INSTANCEOF 136 /* 'instanceof' */
1432#define DUK_HEAP_STRING_INSTANCEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INSTANCEOF)
1433#define DUK_HTHREAD_STRING_INSTANCEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INSTANCEOF)
1434#define DUK_STRIDX_NEW 137 /* 'new' */
1435#define DUK_HEAP_STRING_NEW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_NEW)
1436#define DUK_HTHREAD_STRING_NEW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_NEW)
1437#define DUK_STRIDX_RETURN 138 /* 'return' */
1438#define DUK_HEAP_STRING_RETURN(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_RETURN)
1439#define DUK_HTHREAD_STRING_RETURN(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_RETURN)
1440#define DUK_STRIDX_SWITCH 139 /* 'switch' */
1441#define DUK_HEAP_STRING_SWITCH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SWITCH)
1442#define DUK_HTHREAD_STRING_SWITCH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SWITCH)
1443#define DUK_STRIDX_THIS 140 /* 'this' */
1444#define DUK_HEAP_STRING_THIS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THIS)
1445#define DUK_HTHREAD_STRING_THIS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THIS)
1446#define DUK_STRIDX_THROW 141 /* 'throw' */
1447#define DUK_HEAP_STRING_THROW(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_THROW)
1448#define DUK_HTHREAD_STRING_THROW(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_THROW)
1449#define DUK_STRIDX_TRY 142 /* 'try' */
1450#define DUK_HEAP_STRING_TRY(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRY)
1451#define DUK_HTHREAD_STRING_TRY(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRY)
1452#define DUK_STRIDX_TYPEOF 143 /* 'typeof' */
1453#define DUK_HEAP_STRING_TYPEOF(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TYPEOF)
1454#define DUK_HTHREAD_STRING_TYPEOF(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TYPEOF)
1455#define DUK_STRIDX_VAR 144 /* 'var' */
1456#define DUK_HEAP_STRING_VAR(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VAR)
1457#define DUK_HTHREAD_STRING_VAR(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VAR)
1458#define DUK_STRIDX_CONST 145 /* 'const' */
1459#define DUK_HEAP_STRING_CONST(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CONST)
1460#define DUK_HTHREAD_STRING_CONST(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CONST)
1461#define DUK_STRIDX_VOID 146 /* 'void' */
1462#define DUK_HEAP_STRING_VOID(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_VOID)
1463#define DUK_HTHREAD_STRING_VOID(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_VOID)
1464#define DUK_STRIDX_WHILE 147 /* 'while' */
1465#define DUK_HEAP_STRING_WHILE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WHILE)
1466#define DUK_HTHREAD_STRING_WHILE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WHILE)
1467#define DUK_STRIDX_WITH 148 /* 'with' */
1468#define DUK_HEAP_STRING_WITH(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_WITH)
1469#define DUK_HTHREAD_STRING_WITH(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_WITH)
1470#define DUK_STRIDX_CLASS 149 /* 'class' */
1471#define DUK_HEAP_STRING_CLASS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_CLASS)
1472#define DUK_HTHREAD_STRING_CLASS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_CLASS)
1473#define DUK_STRIDX_ENUM 150 /* 'enum' */
1474#define DUK_HEAP_STRING_ENUM(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_ENUM)
1475#define DUK_HTHREAD_STRING_ENUM(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_ENUM)
1476#define DUK_STRIDX_EXPORT 151 /* 'export' */
1477#define DUK_HEAP_STRING_EXPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXPORT)
1478#define DUK_HTHREAD_STRING_EXPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXPORT)
1479#define DUK_STRIDX_EXTENDS 152 /* 'extends' */
1480#define DUK_HEAP_STRING_EXTENDS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_EXTENDS)
1481#define DUK_HTHREAD_STRING_EXTENDS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_EXTENDS)
1482#define DUK_STRIDX_IMPORT 153 /* 'import' */
1483#define DUK_HEAP_STRING_IMPORT(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPORT)
1484#define DUK_HTHREAD_STRING_IMPORT(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPORT)
1485#define DUK_STRIDX_SUPER 154 /* 'super' */
1486#define DUK_HEAP_STRING_SUPER(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_SUPER)
1487#define DUK_HTHREAD_STRING_SUPER(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_SUPER)
1488#define DUK_STRIDX_LC_NULL 155 /* 'null' */
1489#define DUK_HEAP_STRING_LC_NULL(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LC_NULL)
1490#define DUK_HTHREAD_STRING_LC_NULL(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LC_NULL)
1491#define DUK_STRIDX_TRUE 156 /* 'true' */
1492#define DUK_HEAP_STRING_TRUE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_TRUE)
1493#define DUK_HTHREAD_STRING_TRUE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_TRUE)
1494#define DUK_STRIDX_FALSE 157 /* 'false' */
1495#define DUK_HEAP_STRING_FALSE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_FALSE)
1496#define DUK_HTHREAD_STRING_FALSE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_FALSE)
1497#define DUK_STRIDX_IMPLEMENTS 158 /* 'implements' */
1498#define DUK_HEAP_STRING_IMPLEMENTS(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_IMPLEMENTS)
1499#define DUK_HTHREAD_STRING_IMPLEMENTS(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_IMPLEMENTS)
1500#define DUK_STRIDX_INTERFACE 159 /* 'interface' */
1501#define DUK_HEAP_STRING_INTERFACE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_INTERFACE)
1502#define DUK_HTHREAD_STRING_INTERFACE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_INTERFACE)
1503#define DUK_STRIDX_LET 160 /* 'let' */
1504#define DUK_HEAP_STRING_LET(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_LET)
1505#define DUK_HTHREAD_STRING_LET(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_LET)
1506#define DUK_STRIDX_PACKAGE 161 /* 'package' */
1507#define DUK_HEAP_STRING_PACKAGE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PACKAGE)
1508#define DUK_HTHREAD_STRING_PACKAGE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PACKAGE)
1509#define DUK_STRIDX_PRIVATE 162 /* 'private' */
1510#define DUK_HEAP_STRING_PRIVATE(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PRIVATE)
1511#define DUK_HTHREAD_STRING_PRIVATE(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PRIVATE)
1512#define DUK_STRIDX_PROTECTED 163 /* 'protected' */
1513#define DUK_HEAP_STRING_PROTECTED(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PROTECTED)
1514#define DUK_HTHREAD_STRING_PROTECTED(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PROTECTED)
1515#define DUK_STRIDX_PUBLIC 164 /* 'public' */
1516#define DUK_HEAP_STRING_PUBLIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_PUBLIC)
1517#define DUK_HTHREAD_STRING_PUBLIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_PUBLIC)
1518#define DUK_STRIDX_STATIC 165 /* 'static' */
1519#define DUK_HEAP_STRING_STATIC(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_STATIC)
1520#define DUK_HTHREAD_STRING_STATIC(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_STATIC)
1521#define DUK_STRIDX_YIELD 166 /* 'yield' */
1522#define DUK_HEAP_STRING_YIELD(heap) DUK_HEAP_GET_STRING((heap),DUK_STRIDX_YIELD)
1523#define DUK_HTHREAD_STRING_YIELD(thr) DUK_HTHREAD_GET_STRING((thr),DUK_STRIDX_YIELD)
1524
1525#define DUK_HEAP_NUM_STRINGS 167
1526#define DUK_STRIDX_START_RESERVED 122
1527#define DUK_STRIDX_START_STRICT_RESERVED 158
1528#define DUK_STRIDX_END_RESERVED 167 /* exclusive endpoint */
1529
1530/* To convert a heap stridx to a token number, subtract
1531 * DUK_STRIDX_START_RESERVED and add DUK_TOK_START_RESERVED.
1532 */
1533#if !defined(DUK_SINGLE_FILE)
1534DUK_INTERNAL_DECL const duk_uint8_t duk_strings_data[921];
1535#endif /* !DUK_SINGLE_FILE */
1536#define DUK_STRDATA_MAX_STRLEN 17
1537#define DUK_STRDATA_DATA_LENGTH 921
1538#endif /* DUK_USE_ROM_STRINGS */
1539
1540#if defined(DUK_USE_ROM_OBJECTS)
1541#error RAM support not enabled, rerun configure.py with --ram-support
1542#else /* DUK_USE_ROM_OBJECTS */
1543DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor(duk_context *ctx);
1544DUK_INTERNAL_DECL duk_ret_t duk_bi_function_constructor(duk_context *ctx);
1545DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_context *ctx);
1546DUK_INTERNAL_DECL duk_ret_t duk_bi_array_constructor(duk_context *ctx);
1547DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor(duk_context *ctx);
1548DUK_INTERNAL_DECL duk_ret_t duk_bi_boolean_constructor(duk_context *ctx);
1549DUK_INTERNAL_DECL duk_ret_t duk_bi_number_constructor(duk_context *ctx);
1550DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor(duk_context *ctx);
1551DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx);
1552DUK_INTERNAL_DECL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx);
1553DUK_INTERNAL_DECL duk_ret_t duk_bi_type_error_thrower(duk_context *ctx);
1554DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_constructor(duk_context *ctx);
1555DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_constructor(duk_context *ctx);
1556DUK_INTERNAL_DECL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx);
1557DUK_INTERNAL_DECL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx);
1558DUK_INTERNAL_DECL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx);
1559DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx);
1560DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx);
1561DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_constructor(duk_context *ctx);
1562DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_constructor(duk_context *ctx);
1563DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_eval(duk_context *ctx);
1564DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx);
1565DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx);
1566DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_is_nan(duk_context *ctx);
1567DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_is_finite(duk_context *ctx);
1568DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_decode_uri(duk_context *ctx);
1569DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_decode_uri_component(duk_context *ctx);
1570DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_encode_uri(duk_context *ctx);
1571DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_encode_uri_component(duk_context *ctx);
1572DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_escape(duk_context *ctx);
1573DUK_INTERNAL_DECL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx);
1574DUK_INTERNAL_DECL duk_ret_t duk_bi_object_getprototype_shared(duk_context *ctx);
1575DUK_INTERNAL_DECL duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx);
1576DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_context *ctx);
1577DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx);
1578DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_assign(duk_context *ctx);
1579DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_create(duk_context *ctx);
1580DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_define_property(duk_context *ctx);
1581DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *ctx);
1582DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_context *ctx);
1583DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_context *ctx);
1584DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_context *ctx);
1585DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is_extensible(duk_context *ctx);
1586DUK_INTERNAL_DECL duk_ret_t duk_bi_object_constructor_is(duk_context *ctx);
1587DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_string(duk_context *ctx);
1588DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_context *ctx);
1589DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_value_of(duk_context *ctx);
1590DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_has_own_property(duk_context *ctx);
1591DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_context *ctx);
1592DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_context *ctx);
1593DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx);
1594DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx);
1595DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx);
1596DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx);
1597DUK_INTERNAL_DECL duk_ret_t duk_bi_array_constructor_is_array(duk_context *ctx);
1598DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx);
1599DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx);
1600DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx);
1601DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_pop(duk_context *ctx);
1602DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx);
1603DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_reverse(duk_context *ctx);
1604DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx);
1605DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx);
1606DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_sort(duk_context *ctx);
1607DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx);
1608DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx);
1609DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx);
1610DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx);
1611DUK_INTERNAL_DECL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx);
1612DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor_from_char_code(duk_context *ctx);
1613DUK_INTERNAL_DECL duk_ret_t duk_bi_string_constructor_from_code_point(duk_context *ctx);
1614DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_to_string(duk_context *ctx);
1615DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_char_at(duk_context *ctx);
1616DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_char_code_at(duk_context *ctx);
1617DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_concat(duk_context *ctx);
1618DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_context *ctx);
1619DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_locale_compare(duk_context *ctx);
1620DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_match(duk_context *ctx);
1621DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx);
1622DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx);
1623DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_slice(duk_context *ctx);
1624DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx);
1625DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substring(duk_context *ctx);
1626DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_context *ctx);
1627DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_trim(duk_context *ctx);
1628DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_repeat(duk_context *ctx);
1629DUK_INTERNAL_DECL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx);
1630DUK_INTERNAL_DECL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx);
1631DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_string(duk_context *ctx);
1632DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_context *ctx);
1633DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_value_of(duk_context *ctx);
1634DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_fixed(duk_context *ctx);
1635DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_exponential(duk_context *ctx);
1636DUK_INTERNAL_DECL duk_ret_t duk_bi_number_prototype_to_precision(duk_context *ctx);
1637DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_parse(duk_context *ctx);
1638DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_utc(duk_context *ctx);
1639DUK_INTERNAL_DECL duk_ret_t duk_bi_date_constructor_now(duk_context *ctx);
1640DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_tostring_shared(duk_context *ctx);
1641DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_to_json(duk_context *ctx);
1642DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_value_of(duk_context *ctx);
1643DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_get_shared(duk_context *ctx);
1644DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_context *ctx);
1645DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_set_time(duk_context *ctx);
1646DUK_INTERNAL_DECL duk_ret_t duk_bi_date_prototype_set_shared(duk_context *ctx);
1647DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_exec(duk_context *ctx);
1648DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_test(duk_context *ctx);
1649DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_tostring(duk_context *ctx);
1650DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_flags(duk_context *ctx);
1651DUK_INTERNAL_DECL duk_ret_t duk_bi_regexp_prototype_shared_getter(duk_context *ctx);
1652DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx);
1653DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_stack_setter(duk_context *ctx);
1654DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx);
1655DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_filename_setter(duk_context *ctx);
1656DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx);
1657DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context *ctx);
1658DUK_INTERNAL_DECL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx);
1659DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx);
1660DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx);
1661DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_hypot(duk_context *ctx);
1662DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_max(duk_context *ctx);
1663DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_min(duk_context *ctx);
1664DUK_INTERNAL_DECL duk_ret_t duk_bi_math_object_random(duk_context *ctx);
1665DUK_INTERNAL_DECL duk_ret_t duk_bi_json_object_parse(duk_context *ctx);
1666DUK_INTERNAL_DECL duk_ret_t duk_bi_json_object_stringify(duk_context *ctx);
1667DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_info(duk_context *ctx);
1668DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_act(duk_context *ctx);
1669DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx);
1670DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_fin(duk_context *ctx);
1671DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx);
1672DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_dec(duk_context *ctx);
1673DUK_INTERNAL_DECL duk_ret_t duk_bi_duktape_object_compact(duk_context *ctx);
1674DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_yield(duk_context *ctx);
1675DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_resume(duk_context *ctx);
1676DUK_INTERNAL_DECL duk_ret_t duk_bi_thread_current(duk_context *ctx);
1677DUK_INTERNAL_DECL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_context *ctx);
1678DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_delete_property(duk_context *ctx);
1679DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_get(duk_context *ctx);
1680DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_has(duk_context *ctx);
1681DUK_INTERNAL_DECL duk_ret_t duk_bi_reflect_object_set(duk_context *ctx);
1682DUK_INTERNAL_DECL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx);
1683DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_context *ctx);
1684DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx);
1685DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_context *ctx);
1686DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_buffer_getter(duk_context *ctx);
1687DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx);
1688DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx);
1689DUK_INTERNAL_DECL duk_ret_t duk_bi_typedarray_set(duk_context *ctx);
1690DUK_INTERNAL_DECL duk_ret_t duk_bi_uint8array_allocplain(duk_context *ctx);
1691DUK_INTERNAL_DECL duk_ret_t duk_bi_uint8array_plainof(duk_context *ctx);
1692DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx);
1693DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx);
1694DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx);
1695DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx);
1696DUK_INTERNAL_DECL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx);
1697DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx);
1698DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx);
1699DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx);
1700DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx);
1701DUK_INTERNAL_DECL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx);
1702DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_prototype_encoding_getter(duk_context *ctx);
1703DUK_INTERNAL_DECL duk_ret_t duk_bi_textencoder_prototype_encode(duk_context *ctx);
1704DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_prototype_shared_getter(duk_context *ctx);
1705DUK_INTERNAL_DECL duk_ret_t duk_bi_textdecoder_prototype_decode(duk_context *ctx);
1706#if !defined(DUK_SINGLE_FILE)
1707DUK_INTERNAL_DECL const duk_c_function duk_bi_native_functions[164];
1708#endif /* !DUK_SINGLE_FILE */
1709#define DUK_BIDX_GLOBAL 0
1710#define DUK_BIDX_GLOBAL_ENV 1
1711#define DUK_BIDX_OBJECT_CONSTRUCTOR 2
1712#define DUK_BIDX_OBJECT_PROTOTYPE 3
1713#define DUK_BIDX_FUNCTION_CONSTRUCTOR 4
1714#define DUK_BIDX_FUNCTION_PROTOTYPE 5
1715#define DUK_BIDX_ARRAY_CONSTRUCTOR 6
1716#define DUK_BIDX_ARRAY_PROTOTYPE 7
1717#define DUK_BIDX_STRING_CONSTRUCTOR 8
1718#define DUK_BIDX_STRING_PROTOTYPE 9
1719#define DUK_BIDX_BOOLEAN_CONSTRUCTOR 10
1720#define DUK_BIDX_BOOLEAN_PROTOTYPE 11
1721#define DUK_BIDX_NUMBER_CONSTRUCTOR 12
1722#define DUK_BIDX_NUMBER_PROTOTYPE 13
1723#define DUK_BIDX_DATE_CONSTRUCTOR 14
1724#define DUK_BIDX_DATE_PROTOTYPE 15
1725#define DUK_BIDX_REGEXP_CONSTRUCTOR 16
1726#define DUK_BIDX_REGEXP_PROTOTYPE 17
1727#define DUK_BIDX_ERROR_CONSTRUCTOR 18
1728#define DUK_BIDX_ERROR_PROTOTYPE 19
1729#define DUK_BIDX_EVAL_ERROR_CONSTRUCTOR 20
1730#define DUK_BIDX_EVAL_ERROR_PROTOTYPE 21
1731#define DUK_BIDX_RANGE_ERROR_CONSTRUCTOR 22
1732#define DUK_BIDX_RANGE_ERROR_PROTOTYPE 23
1733#define DUK_BIDX_REFERENCE_ERROR_CONSTRUCTOR 24
1734#define DUK_BIDX_REFERENCE_ERROR_PROTOTYPE 25
1735#define DUK_BIDX_SYNTAX_ERROR_CONSTRUCTOR 26
1736#define DUK_BIDX_SYNTAX_ERROR_PROTOTYPE 27
1737#define DUK_BIDX_TYPE_ERROR_CONSTRUCTOR 28
1738#define DUK_BIDX_TYPE_ERROR_PROTOTYPE 29
1739#define DUK_BIDX_URI_ERROR_CONSTRUCTOR 30
1740#define DUK_BIDX_URI_ERROR_PROTOTYPE 31
1741#define DUK_BIDX_MATH 32
1742#define DUK_BIDX_JSON 33
1743#define DUK_BIDX_TYPE_ERROR_THROWER 34
1744#define DUK_BIDX_DUKTAPE 35
1745#define DUK_BIDX_THREAD_CONSTRUCTOR 36
1746#define DUK_BIDX_THREAD_PROTOTYPE 37
1747#define DUK_BIDX_POINTER_CONSTRUCTOR 38
1748#define DUK_BIDX_POINTER_PROTOTYPE 39
1749#define DUK_BIDX_DOUBLE_ERROR 40
1750#define DUK_BIDX_PROXY_CONSTRUCTOR 41
1751#define DUK_BIDX_REFLECT 42
1752#define DUK_BIDX_SYMBOL_PROTOTYPE 43
1753#define DUK_BIDX_ARRAYBUFFER_CONSTRUCTOR 44
1754#define DUK_BIDX_ARRAYBUFFER_PROTOTYPE 45
1755#define DUK_BIDX_DATAVIEW_CONSTRUCTOR 46
1756#define DUK_BIDX_DATAVIEW_PROTOTYPE 47
1757#define DUK_BIDX_TYPEDARRAY_CONSTRUCTOR 48
1758#define DUK_BIDX_TYPEDARRAY_PROTOTYPE 49
1759#define DUK_BIDX_INT8ARRAY_CONSTRUCTOR 50
1760#define DUK_BIDX_INT8ARRAY_PROTOTYPE 51
1761#define DUK_BIDX_UINT8ARRAY_CONSTRUCTOR 52
1762#define DUK_BIDX_UINT8ARRAY_PROTOTYPE 53
1763#define DUK_BIDX_UINT8CLAMPEDARRAY_CONSTRUCTOR 54
1764#define DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE 55
1765#define DUK_BIDX_INT16ARRAY_CONSTRUCTOR 56
1766#define DUK_BIDX_INT16ARRAY_PROTOTYPE 57
1767#define DUK_BIDX_UINT16ARRAY_CONSTRUCTOR 58
1768#define DUK_BIDX_UINT16ARRAY_PROTOTYPE 59
1769#define DUK_BIDX_INT32ARRAY_CONSTRUCTOR 60
1770#define DUK_BIDX_INT32ARRAY_PROTOTYPE 61
1771#define DUK_BIDX_UINT32ARRAY_CONSTRUCTOR 62
1772#define DUK_BIDX_UINT32ARRAY_PROTOTYPE 63
1773#define DUK_BIDX_FLOAT32ARRAY_CONSTRUCTOR 64
1774#define DUK_BIDX_FLOAT32ARRAY_PROTOTYPE 65
1775#define DUK_BIDX_FLOAT64ARRAY_CONSTRUCTOR 66
1776#define DUK_BIDX_FLOAT64ARRAY_PROTOTYPE 67
1777#define DUK_BIDX_NODEJS_BUFFER_CONSTRUCTOR 68
1778#define DUK_BIDX_NODEJS_BUFFER_PROTOTYPE 69
1779#define DUK_BIDX_TEXTENCODER_CONSTRUCTOR 70
1780#define DUK_BIDX_TEXTENCODER_PROTOTYPE 71
1781#define DUK_BIDX_TEXTDECODER_CONSTRUCTOR 72
1782#define DUK_BIDX_TEXTDECODER_PROTOTYPE 73
1783#define DUK_NUM_BUILTINS 74
1784#define DUK_NUM_BIDX_BUILTINS 74
1785#define DUK_NUM_ALL_BUILTINS 74
1786#if defined(DUK_USE_DOUBLE_LE)
1787#if !defined(DUK_SINGLE_FILE)
1788DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3790];
1789#endif /* !DUK_SINGLE_FILE */
1790#define DUK_BUILTINS_DATA_LENGTH 3790
1791#elif defined(DUK_USE_DOUBLE_BE)
1792#if !defined(DUK_SINGLE_FILE)
1793DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3790];
1794#endif /* !DUK_SINGLE_FILE */
1795#define DUK_BUILTINS_DATA_LENGTH 3790
1796#elif defined(DUK_USE_DOUBLE_ME)
1797#if !defined(DUK_SINGLE_FILE)
1798DUK_INTERNAL_DECL const duk_uint8_t duk_builtins_data[3790];
1799#endif /* !DUK_SINGLE_FILE */
1800#define DUK_BUILTINS_DATA_LENGTH 3790
1801#else
1802#error invalid endianness defines
1803#endif
1804#endif /* DUK_USE_ROM_OBJECTS */
1805#endif /* DUK_BUILTINS_H_INCLUDED */
1806
1807/* #include duk_util.h */
1808/*
1809 * Utilities
1810 */
1811
1812#if !defined(DUK_UTIL_H_INCLUDED)
1813#define DUK_UTIL_H_INCLUDED
1814
1815#define DUK_UTIL_MIN_HASH_PRIME 17 /* must match genhashsizes.py */
1816
1817#define DUK_UTIL_GET_HASH_PROBE_STEP(hash) (duk_util_probe_steps[(hash) & 0x1f])
1818
1819#if defined(DUK_USE_GET_RANDOM_DOUBLE)
1820#define DUK_UTIL_GET_RANDOM_DOUBLE(thr) DUK_USE_GET_RANDOM_DOUBLE((thr)->heap_udata)
1821#else
1822#define DUK_UTIL_GET_RANDOM_DOUBLE(thr) duk_util_tinyrandom_get_double(thr)
1823#endif
1824
1825/*
1826 * Some useful constants
1827 */
1828
1829#define DUK_DOUBLE_2TO32 4294967296.0
1830#define DUK_DOUBLE_2TO31 2147483648.0
1831#define DUK_DOUBLE_LOG2E 1.4426950408889634
1832#define DUK_DOUBLE_LOG10E 0.4342944819032518
1833
1834/*
1835 * Endian conversion
1836 */
1837
1838#if defined(DUK_USE_INTEGER_LE)
1839#define DUK_HTON32(x) DUK_BSWAP32((x))
1840#define DUK_NTOH32(x) DUK_BSWAP32((x))
1841#define DUK_HTON16(x) DUK_BSWAP16((x))
1842#define DUK_NTOH16(x) DUK_BSWAP16((x))
1843#elif defined(DUK_USE_INTEGER_BE)
1844#define DUK_HTON32(x) (x)
1845#define DUK_NTOH32(x) (x)
1846#define DUK_HTON16(x) (x)
1847#define DUK_NTOH16(x) (x)
1848#else
1849#error internal error, endianness defines broken
1850#endif
1851
1852/*
1853 * Bitstream decoder
1854 */
1855
1857 const duk_uint8_t *data;
1858 duk_size_t offset;
1859 duk_size_t length;
1860 duk_uint32_t currval;
1861 duk_small_int_t currbits;
1862};
1863
1864#define DUK_BD_BITPACKED_STRING_MAXLEN 256
1865
1866/*
1867 * Bitstream encoder
1868 */
1869
1871 duk_uint8_t *data;
1872 duk_size_t offset;
1873 duk_size_t length;
1874 duk_uint32_t currval;
1875 duk_small_int_t currbits;
1876 duk_small_int_t truncated;
1877};
1878
1879/*
1880 * Raw write/read macros for big endian, unaligned basic values.
1881 * Caller ensures there's enough space. The macros update the pointer
1882 * argument automatically on resizes. The idiom seems a bit odd, but
1883 * leads to compact code.
1884 */
1885
1886#define DUK_RAW_WRITE_U8(ptr,val) do { \
1887 *(ptr)++ = (duk_uint8_t) (val); \
1888 } while (0)
1889#define DUK_RAW_WRITE_U16_BE(ptr,val) duk_raw_write_u16_be(&(ptr), (duk_uint16_t) (val))
1890#define DUK_RAW_WRITE_U32_BE(ptr,val) duk_raw_write_u32_be(&(ptr), (duk_uint32_t) (val))
1891#define DUK_RAW_WRITE_DOUBLE_BE(ptr,val) duk_raw_write_double_be(&(ptr), (duk_double_t) (val))
1892#define DUK_RAW_WRITE_XUTF8(ptr,val) do { \
1893 /* 'ptr' is evaluated both as LHS and RHS. */ \
1894 duk_uint8_t *duk__ptr; \
1895 duk_small_int_t duk__len; \
1896 duk__ptr = (duk_uint8_t *) (ptr); \
1897 duk__len = duk_unicode_encode_xutf8((duk_ucodepoint_t) (val), duk__ptr); \
1898 duk__ptr += duk__len; \
1899 (ptr) = duk__ptr; \
1900 } while (0)
1901#define DUK_RAW_WRITE_CESU8(ptr,val) do { \
1902 /* 'ptr' is evaluated both as LHS and RHS. */ \
1903 duk_uint8_t *duk__ptr; \
1904 duk_small_int_t duk__len; \
1905 duk__ptr = (duk_uint8_t *) (ptr); \
1906 duk__len = duk_unicode_encode_cesu8((duk_ucodepoint_t) (val), duk__ptr); \
1907 duk__ptr += duk__len; \
1908 (ptr) = duk__ptr; \
1909 } while (0)
1910
1911#define DUK_RAW_READ_U8(ptr) ((duk_uint8_t) (*(ptr)++))
1912#define DUK_RAW_READ_U16_BE(ptr) duk_raw_read_u16_be(&(ptr));
1913#define DUK_RAW_READ_U32_BE(ptr) duk_raw_read_u32_be(&(ptr));
1914#define DUK_RAW_READ_DOUBLE_BE(ptr) duk_raw_read_double_be(&(ptr));
1915
1916/*
1917 * Buffer writer (dynamic buffer only)
1918 *
1919 * Helper for writing to a dynamic buffer with a concept of a "spare" area
1920 * to reduce resizes. You can ensure there is enough space beforehand and
1921 * then write for a while without further checks, relying on a stable data
1922 * pointer. Spare handling is automatic so call sites only indicate how
1923 * much data they need right now.
1924 *
1925 * There are several ways to write using bufwriter. The best approach
1926 * depends mainly on how much performance matters over code footprint.
1927 * The key issues are (1) ensuring there is space and (2) keeping the
1928 * pointers consistent. Fast code should ensure space for multiple writes
1929 * with one ensure call. Fastest inner loop code can temporarily borrow
1930 * the 'p' pointer but must write it back eventually.
1931 *
1932 * Be careful to ensure all macro arguments (other than static pointers like
1933 * 'thr' and 'bw_ctx') are evaluated exactly once, using temporaries if
1934 * necessary (if that's not possible, there should be a note near the macro).
1935 * Buffer write arguments often contain arithmetic etc so this is
1936 * particularly important here.
1937 */
1938
1939/* XXX: Migrate bufwriter and other read/write helpers to its own header? */
1940
1942 duk_uint8_t *p;
1943 duk_uint8_t *p_base;
1944 duk_uint8_t *p_limit;
1946};
1947
1948#define DUK_BW_SPARE_ADD 64
1949#define DUK_BW_SPARE_SHIFT 4 /* 2^4 -> 1/16 = 6.25% spare */
1950
1951/* Initialization and finalization (compaction), converting to other types. */
1952
1953#define DUK_BW_INIT_PUSHBUF(thr,bw_ctx,sz) do { \
1954 duk_bw_init_pushbuf((thr), (bw_ctx), (sz)); \
1955 } while (0)
1956#define DUK_BW_INIT_WITHBUF(thr,bw_ctx,buf) do { \
1957 duk_bw_init((thr), (bw_ctx), (buf)); \
1958 } while (0)
1959#define DUK_BW_COMPACT(thr,bw_ctx) do { \
1960 /* Make underlying buffer compact to match DUK_BW_GET_SIZE(). */ \
1961 duk_bw_compact((thr), (bw_ctx)); \
1962 } while (0)
1963#define DUK_BW_PUSH_AS_STRING(thr,bw_ctx) do { \
1964 duk_push_lstring((duk_context *) (thr), \
1965 (const char *) (bw_ctx)->p_base, \
1966 (duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)); \
1967 } while (0)
1968/* Pointers may be NULL for a while when 'buf' size is zero and before any
1969 * ENSURE calls have been made. Once an ENSURE has been made, the pointers
1970 * are required to be non-NULL so that it's always valid to use memcpy() and
1971 * memmove(), even for zero size.
1972 */
1973#define DUK_BW_ASSERT_VALID_EXPR(thr,bw_ctx) \
1974 DUK_ASSERT_EXPR((bw_ctx) != NULL && \
1975 (bw_ctx)->buf != NULL && \
1976 ((DUK_HBUFFER_DYNAMIC_GET_SIZE((bw_ctx)->buf) == 0) || \
1977 ((bw_ctx)->p != NULL && \
1978 (bw_ctx)->p_base != NULL && \
1979 (bw_ctx)->p_limit != NULL && \
1980 (bw_ctx)->p_limit >= (bw_ctx)->p_base && \
1981 (bw_ctx)->p >= (bw_ctx)->p_base && \
1982 (bw_ctx)->p <= (bw_ctx)->p_limit)))
1983#define DUK_BW_ASSERT_VALID(thr,bw_ctx) do { \
1984 DUK_BW_ASSERT_VALID_EXPR((thr), (bw_ctx)); \
1985 } while (0)
1986
1987/* Working with the pointer and current size. */
1988
1989#define DUK_BW_GET_PTR(thr,bw_ctx) \
1990 ((bw_ctx)->p)
1991#define DUK_BW_SET_PTR(thr,bw_ctx,ptr) do { \
1992 (bw_ctx)->p = (ptr); \
1993 } while (0)
1994#define DUK_BW_ADD_PTR(thr,bw_ctx,delta) do { \
1995 (bw_ctx)->p += (delta); \
1996 } while (0)
1997#define DUK_BW_GET_BASEPTR(thr,bw_ctx) \
1998 ((bw_ctx)->p_base)
1999#define DUK_BW_GET_LIMITPTR(thr,bw_ctx) \
2000 ((bw_ctx)->p_limit)
2001#define DUK_BW_GET_SIZE(thr,bw_ctx) \
2002 ((duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base))
2003#define DUK_BW_SET_SIZE(thr,bw_ctx,sz) do { \
2004 DUK_ASSERT((duk_size_t) (sz) <= (duk_size_t) ((bw_ctx)->p - (bw_ctx)->p_base)); \
2005 (bw_ctx)->p = (bw_ctx)->p_base + (sz); \
2006 } while (0)
2007#define DUK_BW_RESET_SIZE(thr,bw_ctx) do { \
2008 /* Reset to zero size, keep current limit. */ \
2009 (bw_ctx)->p = (bw_ctx)->p_base; \
2010 } while (0)
2011#define DUK_BW_GET_BUFFER(thr,bw_ctx) \
2012 ((bw_ctx)->buf)
2013
2014/* Ensuring (reserving) space. */
2015
2016#define DUK_BW_ENSURE(thr,bw_ctx,sz) do { \
2017 duk_size_t duk__sz, duk__space; \
2018 DUK_BW_ASSERT_VALID((thr), (bw_ctx)); \
2019 duk__sz = (sz); \
2020 duk__space = (duk_size_t) ((bw_ctx)->p_limit - (bw_ctx)->p); \
2021 if (duk__space < duk__sz) { \
2022 (void) duk_bw_resize((thr), (bw_ctx), duk__sz); \
2023 } \
2024 } while (0)
2025/* NOTE: Multiple evaluation of 'ptr' in this macro. */
2026/* XXX: Rework to use an always-inline function? */
2027#define DUK_BW_ENSURE_RAW(thr,bw_ctx,sz,ptr) \
2028 (((duk_size_t) ((bw_ctx)->p_limit - (ptr)) >= (sz)) ? \
2029 (ptr) : \
2030 ((bw_ctx)->p = (ptr), duk_bw_resize((thr),(bw_ctx),(sz))))
2031#define DUK_BW_ENSURE_GETPTR(thr,bw_ctx,sz) \
2032 DUK_BW_ENSURE_RAW((thr), (bw_ctx), (sz), (bw_ctx)->p)
2033#define DUK_BW_ASSERT_SPACE_EXPR(thr,bw_ctx,sz) \
2034 (DUK_BW_ASSERT_VALID_EXPR((thr), (bw_ctx)), \
2035 DUK_ASSERT_EXPR((duk_size_t) ((bw_ctx)->p_limit - (bw_ctx)->p) >= (duk_size_t) (sz)))
2036#define DUK_BW_ASSERT_SPACE(thr,bw_ctx,sz) do { \
2037 DUK_BW_ASSERT_SPACE_EXPR((thr), (bw_ctx), (sz)); \
2038 } while (0)
2039
2040/* Miscellaneous. */
2041
2042#define DUK_BW_SETPTR_AND_COMPACT(thr,bw_ctx,ptr) do { \
2043 (bw_ctx)->p = (ptr); \
2044 duk_bw_compact((thr), (bw_ctx)); \
2045 } while (0)
2046
2047/* Fast write calls which assume you control the spare beforehand.
2048 * Multibyte write variants exist and use a temporary write pointer
2049 * because byte writes alias with anything: with a stored pointer
2050 * explicit pointer load/stores get generated (e.g. gcc -Os).
2051 */
2052
2053#define DUK_BW_WRITE_RAW_U8(thr,bw_ctx,val) do { \
2054 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 1); \
2055 *(bw_ctx)->p++ = (duk_uint8_t) (val); \
2056 } while (0)
2057#define DUK_BW_WRITE_RAW_U8_2(thr,bw_ctx,val1,val2) do { \
2058 duk_uint8_t *duk__p; \
2059 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 2); \
2060 duk__p = (bw_ctx)->p; \
2061 *duk__p++ = (duk_uint8_t) (val1); \
2062 *duk__p++ = (duk_uint8_t) (val2); \
2063 (bw_ctx)->p = duk__p; \
2064 } while (0)
2065#define DUK_BW_WRITE_RAW_U8_3(thr,bw_ctx,val1,val2,val3) do { \
2066 duk_uint8_t *duk__p; \
2067 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 3); \
2068 duk__p = (bw_ctx)->p; \
2069 *duk__p++ = (duk_uint8_t) (val1); \
2070 *duk__p++ = (duk_uint8_t) (val2); \
2071 *duk__p++ = (duk_uint8_t) (val3); \
2072 (bw_ctx)->p = duk__p; \
2073 } while (0)
2074#define DUK_BW_WRITE_RAW_U8_4(thr,bw_ctx,val1,val2,val3,val4) do { \
2075 duk_uint8_t *duk__p; \
2076 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 4); \
2077 duk__p = (bw_ctx)->p; \
2078 *duk__p++ = (duk_uint8_t) (val1); \
2079 *duk__p++ = (duk_uint8_t) (val2); \
2080 *duk__p++ = (duk_uint8_t) (val3); \
2081 *duk__p++ = (duk_uint8_t) (val4); \
2082 (bw_ctx)->p = duk__p; \
2083 } while (0)
2084#define DUK_BW_WRITE_RAW_U8_5(thr,bw_ctx,val1,val2,val3,val4,val5) do { \
2085 duk_uint8_t *duk__p; \
2086 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 5); \
2087 duk__p = (bw_ctx)->p; \
2088 *duk__p++ = (duk_uint8_t) (val1); \
2089 *duk__p++ = (duk_uint8_t) (val2); \
2090 *duk__p++ = (duk_uint8_t) (val3); \
2091 *duk__p++ = (duk_uint8_t) (val4); \
2092 *duk__p++ = (duk_uint8_t) (val5); \
2093 (bw_ctx)->p = duk__p; \
2094 } while (0)
2095#define DUK_BW_WRITE_RAW_U8_6(thr,bw_ctx,val1,val2,val3,val4,val5,val6) do { \
2096 duk_uint8_t *duk__p; \
2097 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), 6); \
2098 duk__p = (bw_ctx)->p; \
2099 *duk__p++ = (duk_uint8_t) (val1); \
2100 *duk__p++ = (duk_uint8_t) (val2); \
2101 *duk__p++ = (duk_uint8_t) (val3); \
2102 *duk__p++ = (duk_uint8_t) (val4); \
2103 *duk__p++ = (duk_uint8_t) (val5); \
2104 *duk__p++ = (duk_uint8_t) (val6); \
2105 (bw_ctx)->p = duk__p; \
2106 } while (0)
2107#define DUK_BW_WRITE_RAW_XUTF8(thr,bw_ctx,cp) do { \
2108 duk_ucodepoint_t duk__cp; \
2109 duk_small_int_t duk__enc_len; \
2110 duk__cp = (cp); \
2111 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), duk_unicode_get_xutf8_length(duk__cp)); \
2112 duk__enc_len = duk_unicode_encode_xutf8(duk__cp, (bw_ctx)->p); \
2113 (bw_ctx)->p += duk__enc_len; \
2114 } while (0)
2115#define DUK_BW_WRITE_RAW_CESU8(thr,bw_ctx,cp) do { \
2116 duk_ucodepoint_t duk__cp; \
2117 duk_small_int_t duk__enc_len; \
2118 duk__cp = (duk_ucodepoint_t) (cp); \
2119 DUK_BW_ASSERT_SPACE((thr), (bw_ctx), duk_unicode_get_cesu8_length(duk__cp)); \
2120 duk__enc_len = duk_unicode_encode_cesu8(duk__cp, (bw_ctx)->p); \
2121 (bw_ctx)->p += duk__enc_len; \
2122 } while (0)
2123/* XXX: add temporary duk__p pointer here too; sharing */
2124#define DUK_BW_WRITE_RAW_BYTES(thr,bw_ctx,valptr,valsz) do { \
2125 const void *duk__valptr; \
2126 duk_size_t duk__valsz; \
2127 duk__valptr = (const void *) (valptr); \
2128 duk__valsz = (duk_size_t) (valsz); \
2129 DUK_MEMCPY((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \
2130 (bw_ctx)->p += duk__valsz; \
2131 } while (0)
2132#define DUK_BW_WRITE_RAW_CSTRING(thr,bw_ctx,val) do { \
2133 const duk_uint8_t *duk__val; \
2134 duk_size_t duk__val_len; \
2135 duk__val = (const duk_uint8_t *) (val); \
2136 duk__val_len = DUK_STRLEN((const char *) duk__val); \
2137 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \
2138 (bw_ctx)->p += duk__val_len; \
2139 } while (0)
2140#define DUK_BW_WRITE_RAW_HSTRING(thr,bw_ctx,val) do { \
2141 duk_size_t duk__val_len; \
2142 duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \
2143 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \
2144 (bw_ctx)->p += duk__val_len; \
2145 } while (0)
2146#define DUK_BW_WRITE_RAW_HBUFFER(thr,bw_ctx,val) do { \
2147 duk_size_t duk__val_len; \
2148 duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \
2149 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2150 (bw_ctx)->p += duk__val_len; \
2151 } while (0)
2152#define DUK_BW_WRITE_RAW_HBUFFER_FIXED(thr,bw_ctx,val) do { \
2153 duk_size_t duk__val_len; \
2154 duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \
2155 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2156 (bw_ctx)->p += duk__val_len; \
2157 } while (0)
2158#define DUK_BW_WRITE_RAW_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \
2159 duk_size_t duk__val_len; \
2160 duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \
2161 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2162 (bw_ctx)->p += duk__val_len; \
2163 } while (0)
2164
2165/* Append bytes from a slice already in the buffer. */
2166#define DUK_BW_WRITE_RAW_SLICE(thr,bw,dst_off,dst_len) \
2167 duk_bw_write_raw_slice((thr), (bw), (dst_off), (dst_len))
2168
2169/* Insert bytes in the middle of the buffer from an external buffer. */
2170#define DUK_BW_INSERT_RAW_BYTES(thr,bw,dst_off,buf,len) \
2171 duk_bw_insert_raw_bytes((thr), (bw), (dst_off), (buf), (len))
2172
2173/* Insert bytes in the middle of the buffer from a slice already
2174 * in the buffer. Source offset is interpreted "before" the operation.
2175 */
2176#define DUK_BW_INSERT_RAW_SLICE(thr,bw,dst_off,src_off,len) \
2177 duk_bw_insert_raw_slice((thr), (bw), (dst_off), (src_off), (len))
2178
2179/* Insert a reserved area somewhere in the buffer; caller fills it.
2180 * Evaluates to a (duk_uint_t *) pointing to the start of the reserved
2181 * area for convenience.
2182 */
2183#define DUK_BW_INSERT_RAW_AREA(thr,bw,off,len) \
2184 duk_bw_insert_raw_area((thr), (bw), (off), (len))
2185
2186/* Remove a slice from inside buffer. */
2187#define DUK_BW_REMOVE_RAW_SLICE(thr,bw,off,len) \
2188 duk_bw_remove_raw_slice((thr), (bw), (off), (len))
2189
2190/* Safe write calls which will ensure space first. */
2191
2192#define DUK_BW_WRITE_ENSURE_U8(thr,bw_ctx,val) do { \
2193 DUK_BW_ENSURE((thr), (bw_ctx), 1); \
2194 DUK_BW_WRITE_RAW_U8((thr), (bw_ctx), (val)); \
2195 } while (0)
2196#define DUK_BW_WRITE_ENSURE_U8_2(thr,bw_ctx,val1,val2) do { \
2197 DUK_BW_ENSURE((thr), (bw_ctx), 2); \
2198 DUK_BW_WRITE_RAW_U8_2((thr), (bw_ctx), (val1), (val2)); \
2199 } while (0)
2200#define DUK_BW_WRITE_ENSURE_U8_3(thr,bw_ctx,val1,val2,val3) do { \
2201 DUK_BW_ENSURE((thr), (bw_ctx), 3); \
2202 DUK_BW_WRITE_RAW_U8_3((thr), (bw_ctx), (val1), (val2), (val3)); \
2203 } while (0)
2204#define DUK_BW_WRITE_ENSURE_U8_4(thr,bw_ctx,val1,val2,val3,val4) do { \
2205 DUK_BW_ENSURE((thr), (bw_ctx), 4); \
2206 DUK_BW_WRITE_RAW_U8_4((thr), (bw_ctx), (val1), (val2), (val3), (val4)); \
2207 } while (0)
2208#define DUK_BW_WRITE_ENSURE_U8_5(thr,bw_ctx,val1,val2,val3,val4,val5) do { \
2209 DUK_BW_ENSURE((thr), (bw_ctx), 5); \
2210 DUK_BW_WRITE_RAW_U8_5((thr), (bw_ctx), (val1), (val2), (val3), (val4), (val5)); \
2211 } while (0)
2212#define DUK_BW_WRITE_ENSURE_U8_6(thr,bw_ctx,val1,val2,val3,val4,val5,val6) do { \
2213 DUK_BW_ENSURE((thr), (bw_ctx), 6); \
2214 DUK_BW_WRITE_RAW_U8_6((thr), (bw_ctx), (val1), (val2), (val3), (val4), (val5), (val6)); \
2215 } while (0)
2216#define DUK_BW_WRITE_ENSURE_XUTF8(thr,bw_ctx,cp) do { \
2217 DUK_BW_ENSURE((thr), (bw_ctx), DUK_UNICODE_MAX_XUTF8_LENGTH); \
2218 DUK_BW_WRITE_RAW_XUTF8((thr), (bw_ctx), (cp)); \
2219 } while (0)
2220#define DUK_BW_WRITE_ENSURE_CESU8(thr,bw_ctx,cp) do { \
2221 DUK_BW_ENSURE((thr), (bw_ctx), DUK_UNICODE_MAX_CESU8_LENGTH); \
2222 DUK_BW_WRITE_RAW_CESU8((thr), (bw_ctx), (cp)); \
2223 } while (0)
2224/* XXX: add temporary duk__p pointer here too; sharing */
2225#define DUK_BW_WRITE_ENSURE_BYTES(thr,bw_ctx,valptr,valsz) do { \
2226 const void *duk__valptr; \
2227 duk_size_t duk__valsz; \
2228 duk__valptr = (const void *) (valptr); \
2229 duk__valsz = (duk_size_t) (valsz); \
2230 DUK_BW_ENSURE((thr), (bw_ctx), duk__valsz); \
2231 DUK_MEMCPY((void *) ((bw_ctx)->p), duk__valptr, duk__valsz); \
2232 (bw_ctx)->p += duk__valsz; \
2233 } while (0)
2234#define DUK_BW_WRITE_ENSURE_CSTRING(thr,bw_ctx,val) do { \
2235 const duk_uint8_t *duk__val; \
2236 duk_size_t duk__val_len; \
2237 duk__val = (const duk_uint8_t *) (val); \
2238 duk__val_len = DUK_STRLEN((const char *) duk__val); \
2239 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
2240 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) duk__val, duk__val_len); \
2241 (bw_ctx)->p += duk__val_len; \
2242 } while (0)
2243#define DUK_BW_WRITE_ENSURE_HSTRING(thr,bw_ctx,val) do { \
2244 duk_size_t duk__val_len; \
2245 duk__val_len = DUK_HSTRING_GET_BYTELEN((val)); \
2246 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
2247 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HSTRING_GET_DATA((val)), duk__val_len); \
2248 (bw_ctx)->p += duk__val_len; \
2249 } while (0)
2250#define DUK_BW_WRITE_ENSURE_HBUFFER(thr,bw_ctx,val) do { \
2251 duk_size_t duk__val_len; \
2252 duk__val_len = DUK_HBUFFER_GET_SIZE((val)); \
2253 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
2254 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2255 (bw_ctx)->p += duk__val_len; \
2256 } while (0)
2257#define DUK_BW_WRITE_ENSURE_HBUFFER_FIXED(thr,bw_ctx,val) do { \
2258 duk_size_t duk__val_len; \
2259 duk__val_len = DUK_HBUFFER_FIXED_GET_SIZE((val)); \
2260 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
2261 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_FIXED_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2262 (bw_ctx)->p += duk__val_len; \
2263 } while (0)
2264#define DUK_BW_WRITE_ENSURE_HBUFFER_DYNAMIC(thr,bw_ctx,val) do { \
2265 duk_size_t duk__val_len; \
2266 duk__val_len = DUK_HBUFFER_DYNAMIC_GET_SIZE((val)); \
2267 DUK_BW_ENSURE((thr), (bw_ctx), duk__val_len); \
2268 DUK_MEMCPY((void *) ((bw_ctx)->p), (const void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((thr)->heap, (val)), duk__val_len); \
2269 (bw_ctx)->p += duk__val_len; \
2270 } while (0)
2271
2272#define DUK_BW_WRITE_ENSURE_SLICE(thr,bw,dst_off,dst_len) \
2273 duk_bw_write_ensure_slice((thr), (bw), (dst_off), (dst_len))
2274#define DUK_BW_INSERT_ENSURE_BYTES(thr,bw,dst_off,buf,len) \
2275 duk_bw_insert_ensure_bytes((thr), (bw), (dst_off), (buf), (len))
2276#define DUK_BW_INSERT_ENSURE_SLICE(thr,bw,dst_off,src_off,len) \
2277 duk_bw_insert_ensure_slice((thr), (bw), (dst_off), (src_off), (len))
2278#define DUK_BW_INSERT_ENSURE_AREA(thr,bw,off,len) \
2279 /* Evaluates to (duk_uint8_t *) pointing to start of area. */ \
2280 duk_bw_insert_ensure_area((thr), (bw), (off), (len))
2281#define DUK_BW_REMOVE_ENSURE_SLICE(thr,bw,off,len) \
2282 /* No difference between raw/ensure because the buffer shrinks. */ \
2283 DUK_BW_REMOVE_RAW_SLICE((thr), (bw), (off), (len))
2284
2285/*
2286 * Externs and prototypes
2287 */
2288
2289#if !defined(DUK_SINGLE_FILE)
2290DUK_INTERNAL_DECL const duk_uint8_t duk_lc_digits[36];
2291DUK_INTERNAL_DECL const duk_uint8_t duk_uc_nybbles[16];
2292DUK_INTERNAL_DECL const duk_int8_t duk_hex_dectab[256];
2293#if defined(DUK_USE_HEX_FASTPATH)
2294DUK_INTERNAL_DECL const duk_int16_t duk_hex_dectab_shift4[256];
2295DUK_INTERNAL_DECL const duk_uint16_t duk_hex_enctab[256];
2296#endif
2297#if defined(DUK_USE_BASE64_FASTPATH)
2298DUK_INTERNAL_DECL const duk_uint8_t duk_base64_enctab[64];
2299DUK_INTERNAL_DECL const duk_int8_t duk_base64_dectab[256];
2300#endif
2301#endif /* !DUK_SINGLE_FILE */
2302
2303/* Note: assumes that duk_util_probe_steps size is 32 */
2304#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE)
2305#if !defined(DUK_SINGLE_FILE)
2306DUK_INTERNAL_DECL duk_uint8_t duk_util_probe_steps[32];
2307#endif /* !DUK_SINGLE_FILE */
2308#endif
2309
2310#if defined(DUK_USE_STRHASH_DENSE)
2311DUK_INTERNAL_DECL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed);
2312#endif
2313
2314#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE)
2315DUK_INTERNAL_DECL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size);
2316#endif
2317
2318DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits);
2319DUK_INTERNAL_DECL duk_small_uint_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx);
2320DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_uint32_t def_value);
2321DUK_INTERNAL_DECL duk_uint32_t duk_bd_decode_varuint(duk_bitdecoder_ctx *ctx);
2322DUK_INTERNAL_DECL duk_small_uint_t duk_bd_decode_bitpacked_string(duk_bitdecoder_ctx *bd, duk_uint8_t *out);
2323
2324DUK_INTERNAL_DECL void duk_be_encode(duk_bitencoder_ctx *ctx, duk_uint32_t data, duk_small_int_t bits);
2325DUK_INTERNAL_DECL void duk_be_finish(duk_bitencoder_ctx *ctx);
2326
2327#if !defined(DUK_USE_GET_RANDOM_DOUBLE)
2328DUK_INTERNAL_DECL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr);
2329DUK_INTERNAL_DECL void duk_util_tinyrandom_prepare_seed(duk_hthread *thr);
2330#endif
2331
2332DUK_INTERNAL_DECL void duk_bw_init(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_hbuffer_dynamic *h_buf);
2333DUK_INTERNAL_DECL void duk_bw_init_pushbuf(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t buf_size);
2334DUK_INTERNAL_DECL duk_uint8_t *duk_bw_resize(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t sz);
2335DUK_INTERNAL_DECL void duk_bw_compact(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx);
2336DUK_INTERNAL_DECL void duk_bw_write_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len);
2337DUK_INTERNAL_DECL void duk_bw_write_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len);
2338DUK_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);
2339DUK_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);
2340DUK_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);
2341DUK_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);
2342DUK_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);
2343DUK_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);
2344DUK_INTERNAL_DECL void duk_bw_remove_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len);
2345/* No duk_bw_remove_ensure_slice(), functionality would be identical. */
2346
2347DUK_INTERNAL_DECL duk_uint16_t duk_raw_read_u16_be(duk_uint8_t **p);
2348DUK_INTERNAL_DECL duk_uint32_t duk_raw_read_u32_be(duk_uint8_t **p);
2349DUK_INTERNAL_DECL duk_double_t duk_raw_read_double_be(duk_uint8_t **p);
2350DUK_INTERNAL_DECL void duk_raw_write_u16_be(duk_uint8_t **p, duk_uint16_t val);
2351DUK_INTERNAL_DECL void duk_raw_write_u32_be(duk_uint8_t **p, duk_uint32_t val);
2352DUK_INTERNAL_DECL void duk_raw_write_double_be(duk_uint8_t **p, duk_double_t val);
2353
2354#if defined(DUK_USE_DEBUGGER_SUPPORT) /* For now only needed by the debugger. */
2355DUK_INTERNAL_DECL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len);
2356#endif
2357
2358DUK_INTERNAL_DECL duk_bool_t duk_is_whole_get_int32_nonegzero(duk_double_t x, duk_int32_t *ival);
2359DUK_INTERNAL_DECL duk_bool_t duk_is_whole_get_int32(duk_double_t x, duk_int32_t *ival);
2360DUK_INTERNAL_DECL duk_bool_t duk_double_is_anyinf(duk_double_t x);
2361DUK_INTERNAL_DECL duk_bool_t duk_double_is_posinf(duk_double_t x);
2362DUK_INTERNAL_DECL duk_bool_t duk_double_is_neginf(duk_double_t x);
2363DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan(duk_double_t x);
2364DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan_or_zero(duk_double_t x);
2365DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan_or_inf(duk_double_t x);
2366DUK_INTERNAL_DECL duk_bool_t duk_double_is_nan_zero_inf(duk_double_t x);
2367DUK_INTERNAL_DECL duk_small_uint_t duk_double_signbit(duk_double_t x);
2368DUK_INTERNAL_DECL duk_double_t duk_double_trunc_towards_zero(duk_double_t x);
2369DUK_INTERNAL_DECL duk_bool_t duk_double_same_sign(duk_double_t x, duk_double_t y);
2370DUK_INTERNAL_DECL duk_double_t duk_double_fmin(duk_double_t x, duk_double_t y);
2371DUK_INTERNAL_DECL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y);
2372
2373#endif /* DUK_UTIL_H_INCLUDED */
2374/* #include duk_strings.h */
2375/*
2376 * Shared string macros.
2377 *
2378 * Using shared macros helps minimize strings data size because it's easy
2379 * to check if an existing string could be used. String constants don't
2380 * need to be all defined here; defining a string here makes sense if there's
2381 * a high chance the string could be reused. Also, using macros allows
2382 * a call site express the exact string needed, but the macro may map to an
2383 * approximate string to reduce unique string count. Macros can also be
2384 * more easily tuned for low memory targets than #if defined()s throughout
2385 * the code base.
2386 *
2387 * Because format strings behave differently in the call site (they need to
2388 * be followed by format arguments), they use a special prefix DUK_STR_FMT_.
2389 *
2390 * On some compilers using explicit shared strings is preferable; on others
2391 * it may be better to use straight literals because the compiler will combine
2392 * them anyway, and such strings won't end up unnecessarily in a symbol table.
2393 */
2394
2395#if !defined(DUK_ERRMSG_H_INCLUDED)
2396#define DUK_ERRMSG_H_INCLUDED
2397
2398/* Mostly API and built-in method related */
2399#define DUK_STR_INTERNAL_ERROR "internal error"
2400#define DUK_STR_UNSUPPORTED "unsupported"
2401#define DUK_STR_INVALID_COUNT "invalid count"
2402#define DUK_STR_INVALID_ARGS "invalid args"
2403#define DUK_STR_INVALID_STATE "invalid state"
2404#define DUK_STR_INVALID_INPUT "invalid input"
2405#define DUK_STR_INVALID_LENGTH "invalid length"
2406#define DUK_STR_NOT_CONSTRUCTABLE "not constructable"
2407#define DUK_STR_CONSTRUCT_ONLY "constructor requires 'new'"
2408#define DUK_STR_NOT_CALLABLE "not callable"
2409#define DUK_STR_NOT_EXTENSIBLE "not extensible"
2410#define DUK_STR_NOT_WRITABLE "not writable"
2411#define DUK_STR_NOT_CONFIGURABLE "not configurable"
2412#define DUK_STR_INVALID_CONTEXT "invalid context"
2413#define DUK_STR_INVALID_INDEX "invalid args"
2414#define DUK_STR_PUSH_BEYOND_ALLOC_STACK "cannot push beyond allocated stack"
2415#define DUK_STR_NOT_UNDEFINED "unexpected type"
2416#define DUK_STR_NOT_NULL "unexpected type"
2417#define DUK_STR_NOT_BOOLEAN "unexpected type"
2418#define DUK_STR_NOT_NUMBER "unexpected type"
2419#define DUK_STR_NOT_STRING "unexpected type"
2420#define DUK_STR_NOT_OBJECT "unexpected type"
2421#define DUK_STR_NOT_POINTER "unexpected type"
2422#define DUK_STR_NOT_BUFFER "not buffer" /* still in use with verbose messages */
2423#define DUK_STR_UNEXPECTED_TYPE "unexpected type"
2424#define DUK_STR_NOT_THREAD "unexpected type"
2425#define DUK_STR_NOT_COMPFUNC "unexpected type"
2426#define DUK_STR_NOT_NATFUNC "unexpected type"
2427#define DUK_STR_NOT_C_FUNCTION "unexpected type"
2428#define DUK_STR_NOT_FUNCTION "unexpected type"
2429#define DUK_STR_NOT_REGEXP "unexpected type"
2430#define DUK_STR_TOPRIMITIVE_FAILED "coercion to primitive failed"
2431#define DUK_STR_NUMBER_OUTSIDE_RANGE "number outside range"
2432#define DUK_STR_NOT_OBJECT_COERCIBLE "not object coercible"
2433#define DUK_STR_CANNOT_NUMBER_COERCE_SYMBOL "cannot number coerce Symbol"
2434#define DUK_STR_CANNOT_STRING_COERCE_SYMBOL "cannot string coerce Symbol"
2435#define DUK_STR_STRING_TOO_LONG "string too long"
2436#define DUK_STR_BUFFER_TOO_LONG "buffer too long"
2437#define DUK_STR_ALLOC_FAILED "alloc failed"
2438#define DUK_STR_WRONG_BUFFER_TYPE "wrong buffer type"
2439#define DUK_STR_ENCODE_FAILED "encode failed"
2440#define DUK_STR_DECODE_FAILED "decode failed"
2441#define DUK_STR_NO_SOURCECODE "no sourcecode"
2442#define DUK_STR_RESULT_TOO_LONG "result too long"
2443
2444/* JSON */
2445#define DUK_STR_FMT_PTR "%p"
2446#define DUK_STR_FMT_INVALID_JSON "invalid json (at offset %ld)"
2447#define DUK_STR_JSONDEC_RECLIMIT "json decode recursion limit"
2448#define DUK_STR_JSONENC_RECLIMIT "json encode recursion limit"
2449#define DUK_STR_CYCLIC_INPUT "cyclic input"
2450
2451/* Object property access */
2452#define DUK_STR_PROXY_REVOKED "proxy revoked"
2453#define DUK_STR_INVALID_BASE "invalid base value"
2454#define DUK_STR_STRICT_CALLER_READ "cannot read strict 'caller'"
2455#define DUK_STR_PROXY_REJECTED "proxy rejected"
2456#define DUK_STR_INVALID_ARRAY_LENGTH "invalid array length"
2457#define DUK_STR_SETTER_UNDEFINED "setter undefined"
2458#define DUK_STR_INVALID_DESCRIPTOR "invalid descriptor"
2459
2460/* Proxy */
2461#define DUK_STR_INVALID_TRAP_RESULT "invalid trap result"
2462
2463/* Variables */
2464
2465/* Lexer */
2466#define DUK_STR_INVALID_ESCAPE "invalid escape"
2467#define DUK_STR_UNTERMINATED_STRING "unterminated string"
2468#define DUK_STR_UNTERMINATED_COMMENT "unterminated comment"
2469#define DUK_STR_UNTERMINATED_REGEXP "unterminated regexp"
2470#define DUK_STR_TOKEN_LIMIT "token limit"
2471#define DUK_STR_REGEXP_SUPPORT_DISABLED "regexp support disabled"
2472#define DUK_STR_INVALID_NUMBER_LITERAL "invalid number literal"
2473#define DUK_STR_INVALID_TOKEN "invalid token"
2474
2475/* Compiler */
2476#define DUK_STR_PARSE_ERROR "parse error"
2477#define DUK_STR_DUPLICATE_LABEL "duplicate label"
2478#define DUK_STR_INVALID_LABEL "invalid label"
2479#define DUK_STR_INVALID_ARRAY_LITERAL "invalid array literal"
2480#define DUK_STR_INVALID_OBJECT_LITERAL "invalid object literal"
2481#define DUK_STR_INVALID_VAR_DECLARATION "invalid variable declaration"
2482#define DUK_STR_CANNOT_DELETE_IDENTIFIER "cannot delete identifier"
2483#define DUK_STR_INVALID_EXPRESSION "invalid expression"
2484#define DUK_STR_INVALID_LVALUE "invalid lvalue"
2485#define DUK_STR_EXPECTED_IDENTIFIER "expected identifier"
2486#define DUK_STR_EMPTY_EXPR_NOT_ALLOWED "empty expression not allowed"
2487#define DUK_STR_INVALID_FOR "invalid for statement"
2488#define DUK_STR_INVALID_SWITCH "invalid switch statement"
2489#define DUK_STR_INVALID_BREAK_CONT_LABEL "invalid break/continue label"
2490#define DUK_STR_INVALID_RETURN "invalid return"
2491#define DUK_STR_INVALID_TRY "invalid try"
2492#define DUK_STR_INVALID_THROW "invalid throw"
2493#define DUK_STR_WITH_IN_STRICT_MODE "with in strict mode"
2494#define DUK_STR_FUNC_STMT_NOT_ALLOWED "function statement not allowed"
2495#define DUK_STR_UNTERMINATED_STMT "unterminated statement"
2496#define DUK_STR_INVALID_ARG_NAME "invalid argument name"
2497#define DUK_STR_INVALID_FUNC_NAME "invalid function name"
2498#define DUK_STR_INVALID_GETSET_NAME "invalid getter/setter name"
2499#define DUK_STR_FUNC_NAME_REQUIRED "function name required"
2500
2501/* Regexp */
2502#define DUK_STR_INVALID_QUANTIFIER "invalid regexp quantifier"
2503#define DUK_STR_INVALID_QUANTIFIER_NO_ATOM "quantifier without preceding atom"
2504#define DUK_STR_INVALID_QUANTIFIER_VALUES "quantifier values invalid (qmin > qmax)"
2505#define DUK_STR_QUANTIFIER_TOO_MANY_COPIES "quantifier requires too many atom copies"
2506#define DUK_STR_UNEXPECTED_CLOSING_PAREN "unexpected closing parenthesis"
2507#define DUK_STR_UNEXPECTED_END_OF_PATTERN "unexpected end of pattern"
2508#define DUK_STR_UNEXPECTED_REGEXP_TOKEN "unexpected token in regexp"
2509#define DUK_STR_INVALID_REGEXP_FLAGS "invalid regexp flags"
2510#define DUK_STR_INVALID_REGEXP_ESCAPE "invalid regexp escape"
2511#define DUK_STR_INVALID_BACKREFS "invalid backreference(s)"
2512#define DUK_STR_INVALID_REGEXP_CHARACTER "invalid regexp character"
2513#define DUK_STR_UNTERMINATED_CHARCLASS "unterminated character class"
2514#define DUK_STR_INVALID_RANGE "invalid range"
2515
2516/* Limits */
2517#define DUK_STR_VALSTACK_LIMIT "valstack limit"
2518#define DUK_STR_CALLSTACK_LIMIT "callstack limit"
2519#define DUK_STR_CATCHSTACK_LIMIT "catchstack limit"
2520#define DUK_STR_PROTOTYPE_CHAIN_LIMIT "prototype chain limit"
2521#define DUK_STR_BOUND_CHAIN_LIMIT "function call bound chain limit"
2522#define DUK_STR_C_CALLSTACK_LIMIT "C call stack depth limit"
2523#define DUK_STR_COMPILER_RECURSION_LIMIT "compiler recursion limit"
2524#define DUK_STR_BYTECODE_LIMIT "bytecode limit"
2525#define DUK_STR_REG_LIMIT "register limit"
2526#define DUK_STR_TEMP_LIMIT "temp limit"
2527#define DUK_STR_CONST_LIMIT "const limit"
2528#define DUK_STR_FUNC_LIMIT "function limit"
2529#define DUK_STR_REGEXP_COMPILER_RECURSION_LIMIT "regexp compiler recursion limit"
2530#define DUK_STR_REGEXP_EXECUTOR_RECURSION_LIMIT "regexp executor recursion limit"
2531#define DUK_STR_REGEXP_EXECUTOR_STEP_LIMIT "regexp step limit"
2532
2533#endif /* DUK_ERRMSG_H_INCLUDED */
2534/* #include duk_js_bytecode.h */
2535/*
2536 * Ecmascript bytecode
2537 */
2538
2539#if !defined(DUK_JS_BYTECODE_H_INCLUDED)
2540#define DUK_JS_BYTECODE_H_INCLUDED
2541
2542/*
2543 * Bytecode instruction layout
2544 * ===========================
2545 *
2546 * Instructions are unsigned 32-bit integers divided as follows:
2547 *
2548 * !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! !
2549 * !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!
2550 * +-----------------------------------------------+---------------+
2551 * ! C ! B ! A ! OP !
2552 * +-----------------------------------------------+---------------+
2553 *
2554 * OP (8 bits): opcode (DUK_OP_*), access should be fastest
2555 * consecutive opcodes allocated when opcode needs flags
2556 * A (8 bits): typically a target register number
2557 * B (8 bits): typically first source register/constant number
2558 * C (8 bits): typically second source register/constant number
2559 *
2560 * Some instructions combine BC or ABC together for larger parameter values.
2561 * Signed integers (e.g. jump offsets) are encoded as unsigned, with an
2562 * opcode specific bias.
2563 *
2564 * Some opcodes have flags which are handled by allocating consecutive
2565 * opcodes to make space for 1-N flags. Flags can also be e.g. in the 'A'
2566 * field when there's room for the specific opcode.
2567 *
2568 * For example, if three flags were needed, they could be allocated from
2569 * the opcode field as follows:
2570 *
2571 * !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! !
2572 * !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!
2573 * +-----------------------------------------------+---------------+
2574 * ! C ! B ! A ! OP !Z!Y!X!
2575 * +-----------------------------------------------+---------------+
2576 *
2577 * Some opcodes accept a reg/const argument which is handled by allocating
2578 * flags in the OP field, see DUK_BC_ISREG() and DUK_BC_ISCONST(). The
2579 * following convention is shared by most opcodes, so that the compiler
2580 * can handle reg/const flagging without opcode specific code paths:
2581 *
2582 * !3!3!2!2!2!2!2!2!2!2!2!2!1!1!1!1!1!1!1!1!1!1! ! ! ! ! ! ! ! ! ! !
2583 * !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!
2584 * +-----------------------------------------------+---------------+
2585 * ! C ! B ! A ! OP !Y!X!
2586 * +-----------------------------------------------+---------------+
2587 *
2588 * X 1=B is const, 0=B is reg
2589 * Y 1=C is const, 0=C is reg
2590 *
2591 * In effect OP, OP + 1, OP + 2, and OP + 3 are allocated from the
2592 * 8-bit opcode space for a single logical opcode. The base opcode
2593 * number should be divisible by 4. If the opcode is called 'FOO'
2594 * the following opcode constants would be defined:
2595 *
2596 * DUK_OP_FOO 100 // base opcode number
2597 * DUK_OP_FOO_RR 100 // FOO, B=reg, C=reg
2598 * DUK_OP_FOO_CR 101 // FOO, B=const, C=reg
2599 * DUK_OP_FOO_RC 102 // FOO, B=reg, C=const
2600 * DUK_OP_FOO_CC 103 // FOO, B=const, C=const
2601 *
2602 * If only B or C is a reg/const, the unused opcode combinations can be
2603 * used for other opcodes (which take no reg/const argument). However,
2604 * such opcode values are initially reserved, at least while opcode space
2605 * is available. For example, if 'BAR' uses B for a register field and
2606 * C is a reg/const:
2607 *
2608 * DUK_OP_BAR 116 // base opcode number
2609 * DUK_OP_BAR_RR 116 // BAR, B=reg, C=reg
2610 * DUK_OP_BAR_CR_UNUSED 117 // unused, could be repurposed
2611 * DUK_OP_BAR_RC 118 // BAR, B=reg, C=const
2612 * DUK_OP_BAR_CC_UNUSED 119 // unused, could be repurposed
2613 *
2614 * Macro naming is a bit misleading, e.g. "ABC" in macro name but the
2615 * field layout is concretely "CBA" in the register.
2616 */
2617
2618typedef duk_uint32_t duk_instr_t;
2619
2620#define DUK_BC_SHIFT_OP 0
2621#define DUK_BC_SHIFT_A 8
2622#define DUK_BC_SHIFT_B 16
2623#define DUK_BC_SHIFT_C 24
2624#define DUK_BC_SHIFT_BC DUK_BC_SHIFT_B
2625#define DUK_BC_SHIFT_ABC DUK_BC_SHIFT_A
2626
2627#define DUK_BC_UNSHIFTED_MASK_OP 0xffUL
2628#define DUK_BC_UNSHIFTED_MASK_A 0xffUL
2629#define DUK_BC_UNSHIFTED_MASK_B 0xffUL
2630#define DUK_BC_UNSHIFTED_MASK_C 0xffUL
2631#define DUK_BC_UNSHIFTED_MASK_BC 0xffffUL
2632#define DUK_BC_UNSHIFTED_MASK_ABC 0xffffffUL
2633
2634#define DUK_BC_SHIFTED_MASK_OP (DUK_BC_UNSHIFTED_MASK_OP << DUK_BC_SHIFT_OP)
2635#define DUK_BC_SHIFTED_MASK_A (DUK_BC_UNSHIFTED_MASK_A << DUK_BC_SHIFT_A)
2636#define DUK_BC_SHIFTED_MASK_B (DUK_BC_UNSHIFTED_MASK_B << DUK_BC_SHIFT_B)
2637#define DUK_BC_SHIFTED_MASK_C (DUK_BC_UNSHIFTED_MASK_C << DUK_BC_SHIFT_C)
2638#define DUK_BC_SHIFTED_MASK_BC (DUK_BC_UNSHIFTED_MASK_BC << DUK_BC_SHIFT_BC)
2639#define DUK_BC_SHIFTED_MASK_ABC (DUK_BC_UNSHIFTED_MASK_ABC << DUK_BC_SHIFT_ABC)
2640
2641#define DUK_DEC_OP(x) ((x) & 0xffUL)
2642#define DUK_DEC_A(x) (((x) >> 8) & 0xffUL)
2643#define DUK_DEC_B(x) (((x) >> 16) & 0xffUL)
2644#define DUK_DEC_C(x) (((x) >> 24) & 0xffUL)
2645#define DUK_DEC_BC(x) (((x) >> 16) & 0xffffUL)
2646#define DUK_DEC_ABC(x) (((x) >> 8) & 0xffffffUL)
2647
2648#define DUK_ENC_OP(op) ((duk_instr_t) (op))
2649#define DUK_ENC_OP_ABC(op,abc) ((duk_instr_t) ( \
2650 (((duk_instr_t) (abc)) << 8) | \
2651 ((duk_instr_t) (op)) \
2652 ))
2653#define DUK_ENC_OP_A_BC(op,a,bc) ((duk_instr_t) ( \
2654 (((duk_instr_t) (bc)) << 16) | \
2655 (((duk_instr_t) (a)) << 8) | \
2656 ((duk_instr_t) (op)) \
2657 ))
2658#define DUK_ENC_OP_A_B_C(op,a,b,c) ((duk_instr_t) ( \
2659 (((duk_instr_t) (c)) << 24) | \
2660 (((duk_instr_t) (b)) << 16) | \
2661 (((duk_instr_t) (a)) << 8) | \
2662 ((duk_instr_t) (op)) \
2663 ))
2664#define DUK_ENC_OP_A_B(op,a,b) DUK_ENC_OP_A_B_C((op),(a),(b),0)
2665#define DUK_ENC_OP_A(op,a) DUK_ENC_OP_A_B_C((op),(a),0,0)
2666#define DUK_ENC_OP_BC(op,bc) DUK_ENC_OP_A_BC((op),0,(bc))
2667
2668/* Get opcode base value with B/C reg/const flags cleared. */
2669#define DUK_BC_NOREGCONST_OP(op) ((op) & 0xfc)
2670
2671/* Constants should be signed so that signed arithmetic involving them
2672 * won't cause values to be coerced accidentally to unsigned.
2673 */
2674#define DUK_BC_OP_MIN 0
2675#define DUK_BC_OP_MAX 0xffL
2676#define DUK_BC_A_MIN 0
2677#define DUK_BC_A_MAX 0xffL
2678#define DUK_BC_B_MIN 0
2679#define DUK_BC_B_MAX 0xffL
2680#define DUK_BC_C_MIN 0
2681#define DUK_BC_C_MAX 0xffL
2682#define DUK_BC_BC_MIN 0
2683#define DUK_BC_BC_MAX 0xffffL
2684#define DUK_BC_ABC_MIN 0
2685#define DUK_BC_ABC_MAX 0xffffffL
2686
2687/* Masks for B/C reg/const indicator in opcode field. */
2688#define DUK_BC_REGCONST_B (0x01UL)
2689#define DUK_BC_REGCONST_C (0x02UL)
2690
2691/* Misc. masks for opcode field. */
2692#define DUK_BC_INCDECP_FLAG_DEC (0x04UL)
2693#define DUK_BC_INCDECP_FLAG_POST (0x08UL)
2694
2695/* Opcodes. */
2696#define DUK_OP_LDREG 0
2697#define DUK_OP_STREG 1
2698#define DUK_OP_LDCONST 2
2699#define DUK_OP_LDINT 3
2700#define DUK_OP_LDINTX 4
2701#define DUK_OP_LDTHIS 5
2702#define DUK_OP_LDUNDEF 6
2703#define DUK_OP_LDNULL 7
2704#define DUK_OP_LDTRUE 8
2705#define DUK_OP_LDFALSE 9
2706#define DUK_OP_BNOT 10
2707#define DUK_OP_LNOT 11
2708#define DUK_OP_UNM 12
2709#define DUK_OP_UNP 13
2710#define DUK_OP_TYPEOF 14
2711#define DUK_OP_TYPEOFID 15
2712#define DUK_OP_EQ 16
2713#define DUK_OP_EQ_RR 16
2714#define DUK_OP_EQ_CR 17
2715#define DUK_OP_EQ_RC 18
2716#define DUK_OP_EQ_CC 19
2717#define DUK_OP_NEQ 20
2718#define DUK_OP_NEQ_RR 20
2719#define DUK_OP_NEQ_CR 21
2720#define DUK_OP_NEQ_RC 22
2721#define DUK_OP_NEQ_CC 23
2722#define DUK_OP_SEQ 24
2723#define DUK_OP_SEQ_RR 24
2724#define DUK_OP_SEQ_CR 25
2725#define DUK_OP_SEQ_RC 26
2726#define DUK_OP_SEQ_CC 27
2727#define DUK_OP_SNEQ 28
2728#define DUK_OP_SNEQ_RR 28
2729#define DUK_OP_SNEQ_CR 29
2730#define DUK_OP_SNEQ_RC 30
2731#define DUK_OP_SNEQ_CC 31
2732#define DUK_OP_GT 32
2733#define DUK_OP_GT_RR 32
2734#define DUK_OP_GT_CR 33
2735#define DUK_OP_GT_RC 34
2736#define DUK_OP_GT_CC 35
2737#define DUK_OP_GE 36
2738#define DUK_OP_GE_RR 36
2739#define DUK_OP_GE_CR 37
2740#define DUK_OP_GE_RC 38
2741#define DUK_OP_GE_CC 39
2742#define DUK_OP_LT 40
2743#define DUK_OP_LT_RR 40
2744#define DUK_OP_LT_CR 41
2745#define DUK_OP_LT_RC 42
2746#define DUK_OP_LT_CC 43
2747#define DUK_OP_LE 44
2748#define DUK_OP_LE_RR 44
2749#define DUK_OP_LE_CR 45
2750#define DUK_OP_LE_RC 46
2751#define DUK_OP_LE_CC 47
2752#define DUK_OP_IFTRUE 48
2753#define DUK_OP_IFTRUE_R 48
2754#define DUK_OP_IFTRUE_C 49
2755#define DUK_OP_IFFALSE 50
2756#define DUK_OP_IFFALSE_R 50
2757#define DUK_OP_IFFALSE_C 51
2758#define DUK_OP_ADD 52
2759#define DUK_OP_ADD_RR 52
2760#define DUK_OP_ADD_CR 53
2761#define DUK_OP_ADD_RC 54
2762#define DUK_OP_ADD_CC 55
2763#define DUK_OP_SUB 56
2764#define DUK_OP_SUB_RR 56
2765#define DUK_OP_SUB_CR 57
2766#define DUK_OP_SUB_RC 58
2767#define DUK_OP_SUB_CC 59
2768#define DUK_OP_MUL 60
2769#define DUK_OP_MUL_RR 60
2770#define DUK_OP_MUL_CR 61
2771#define DUK_OP_MUL_RC 62
2772#define DUK_OP_MUL_CC 63
2773#define DUK_OP_DIV 64
2774#define DUK_OP_DIV_RR 64
2775#define DUK_OP_DIV_CR 65
2776#define DUK_OP_DIV_RC 66
2777#define DUK_OP_DIV_CC 67
2778#define DUK_OP_MOD 68
2779#define DUK_OP_MOD_RR 68
2780#define DUK_OP_MOD_CR 69
2781#define DUK_OP_MOD_RC 70
2782#define DUK_OP_MOD_CC 71
2783#define DUK_OP_EXP 72
2784#define DUK_OP_EXP_RR 72
2785#define DUK_OP_EXP_CR 73
2786#define DUK_OP_EXP_RC 74
2787#define DUK_OP_EXP_CC 75
2788#define DUK_OP_BAND 76
2789#define DUK_OP_BAND_RR 76
2790#define DUK_OP_BAND_CR 77
2791#define DUK_OP_BAND_RC 78
2792#define DUK_OP_BAND_CC 79
2793#define DUK_OP_BOR 80
2794#define DUK_OP_BOR_RR 80
2795#define DUK_OP_BOR_CR 81
2796#define DUK_OP_BOR_RC 82
2797#define DUK_OP_BOR_CC 83
2798#define DUK_OP_BXOR 84
2799#define DUK_OP_BXOR_RR 84
2800#define DUK_OP_BXOR_CR 85
2801#define DUK_OP_BXOR_RC 86
2802#define DUK_OP_BXOR_CC 87
2803#define DUK_OP_BASL 88
2804#define DUK_OP_BASL_RR 88
2805#define DUK_OP_BASL_CR 89
2806#define DUK_OP_BASL_RC 90
2807#define DUK_OP_BASL_CC 91
2808#define DUK_OP_BLSR 92
2809#define DUK_OP_BLSR_RR 92
2810#define DUK_OP_BLSR_CR 93
2811#define DUK_OP_BLSR_RC 94
2812#define DUK_OP_BLSR_CC 95
2813#define DUK_OP_BASR 96
2814#define DUK_OP_BASR_RR 96
2815#define DUK_OP_BASR_CR 97
2816#define DUK_OP_BASR_RC 98
2817#define DUK_OP_BASR_CC 99
2818#define DUK_OP_INSTOF 100
2819#define DUK_OP_INSTOF_RR 100
2820#define DUK_OP_INSTOF_CR 101
2821#define DUK_OP_INSTOF_RC 102
2822#define DUK_OP_INSTOF_CC 103
2823#define DUK_OP_IN 104
2824#define DUK_OP_IN_RR 104
2825#define DUK_OP_IN_CR 105
2826#define DUK_OP_IN_RC 106
2827#define DUK_OP_IN_CC 107
2828#define DUK_OP_GETPROP 108
2829#define DUK_OP_GETPROP_RR 108
2830#define DUK_OP_GETPROP_CR 109
2831#define DUK_OP_GETPROP_RC 110
2832#define DUK_OP_GETPROP_CC 111
2833#define DUK_OP_PUTPROP 112
2834#define DUK_OP_PUTPROP_RR 112
2835#define DUK_OP_PUTPROP_CR 113
2836#define DUK_OP_PUTPROP_RC 114
2837#define DUK_OP_PUTPROP_CC 115
2838#define DUK_OP_DELPROP 116
2839#define DUK_OP_DELPROP_RR 116
2840#define DUK_OP_DELPROP_CR_UNUSED 117 /* unused now */
2841#define DUK_OP_DELPROP_RC 118
2842#define DUK_OP_DELPROP_CC_UNUSED 119 /* unused now */
2843#define DUK_OP_PREINCR 120 /* pre/post opcode values have constraints, */
2844#define DUK_OP_PREDECR 121 /* see duk_js_executor.c and duk_js_compiler.c. */
2845#define DUK_OP_POSTINCR 122
2846#define DUK_OP_POSTDECR 123
2847#define DUK_OP_PREINCV 124
2848#define DUK_OP_PREDECV 125
2849#define DUK_OP_POSTINCV 126
2850#define DUK_OP_POSTDECV 127
2851#define DUK_OP_PREINCP 128 /* pre/post inc/dec prop opcodes have constraints */
2852#define DUK_OP_PREINCP_RR 128
2853#define DUK_OP_PREINCP_CR 129
2854#define DUK_OP_PREINCP_RC 130
2855#define DUK_OP_PREINCP_CC 131
2856#define DUK_OP_PREDECP 132
2857#define DUK_OP_PREDECP_RR 132
2858#define DUK_OP_PREDECP_CR 133
2859#define DUK_OP_PREDECP_RC 134
2860#define DUK_OP_PREDECP_CC 135
2861#define DUK_OP_POSTINCP 136
2862#define DUK_OP_POSTINCP_RR 136
2863#define DUK_OP_POSTINCP_CR 137
2864#define DUK_OP_POSTINCP_RC 138
2865#define DUK_OP_POSTINCP_CC 139
2866#define DUK_OP_POSTDECP 140
2867#define DUK_OP_POSTDECP_RR 140
2868#define DUK_OP_POSTDECP_CR 141
2869#define DUK_OP_POSTDECP_RC 142
2870#define DUK_OP_POSTDECP_CC 143
2871#define DUK_OP_DECLVAR 144
2872#define DUK_OP_DECLVAR_RR 144
2873#define DUK_OP_DECLVAR_CR 145
2874#define DUK_OP_DECLVAR_RC 146
2875#define DUK_OP_DECLVAR_CC 147
2876#define DUK_OP_REGEXP 148
2877#define DUK_OP_REGEXP_RR 148
2878#define DUK_OP_REGEXP_CR 149
2879#define DUK_OP_REGEXP_RC 150
2880#define DUK_OP_REGEXP_CC 151
2881#define DUK_OP_CSVAR 152
2882#define DUK_OP_CSVAR_RR 152
2883#define DUK_OP_CSVAR_CR 153
2884#define DUK_OP_CSVAR_RC 154
2885#define DUK_OP_CSVAR_CC 155
2886#define DUK_OP_CLOSURE 156
2887#define DUK_OP_GETVAR 157
2888#define DUK_OP_PUTVAR 158
2889#define DUK_OP_DELVAR 159
2890#define DUK_OP_JUMP 160
2891#define DUK_OP_RETREG 161
2892#define DUK_OP_RETUNDEF 162
2893#define DUK_OP_RETCONST 163
2894#define DUK_OP_RETCONSTN 164 /* return const without incref (e.g. number) */
2895#define DUK_OP_LABEL 165
2896#define DUK_OP_ENDLABEL 166
2897#define DUK_OP_BREAK 167
2898#define DUK_OP_CONTINUE 168
2899#define DUK_OP_TRYCATCH 169
2900#define DUK_OP_ENDTRY 170
2901#define DUK_OP_ENDCATCH 171
2902#define DUK_OP_ENDFIN 172
2903#define DUK_OP_THROW 173
2904#define DUK_OP_CSREG 174
2905#define DUK_OP_EVALCALL 175
2906#define DUK_OP_CALL 176 /* must be even */
2907#define DUK_OP_TAILCALL 177 /* must be odd */
2908#define DUK_OP_NEW 178
2909#define DUK_OP_NEWOBJ 179
2910#define DUK_OP_NEWARR 180
2911#define DUK_OP_MPUTOBJ 181
2912#define DUK_OP_MPUTOBJI 182
2913#define DUK_OP_INITSET 183
2914#define DUK_OP_INITGET 184
2915#define DUK_OP_MPUTARR 185
2916#define DUK_OP_MPUTARRI 186
2917#define DUK_OP_SETALEN 187
2918#define DUK_OP_INITENUM 188
2919#define DUK_OP_NEXTENUM 189
2920#define DUK_OP_INVLHS 190
2921#define DUK_OP_DEBUGGER 191
2922#define DUK_OP_NOP 192
2923#define DUK_OP_INVALID 193
2924#define DUK_OP_UNUSED194 194
2925#define DUK_OP_UNUSED195 195
2926#define DUK_OP_UNUSED196 196
2927#define DUK_OP_UNUSED197 197
2928#define DUK_OP_UNUSED198 198
2929#define DUK_OP_UNUSED199 199
2930#define DUK_OP_UNUSED200 200
2931#define DUK_OP_UNUSED201 201
2932#define DUK_OP_UNUSED202 202
2933#define DUK_OP_UNUSED203 203
2934#define DUK_OP_UNUSED204 204
2935#define DUK_OP_UNUSED205 205
2936#define DUK_OP_UNUSED206 206
2937#define DUK_OP_UNUSED207 207
2938#define DUK_OP_UNUSED208 208
2939#define DUK_OP_UNUSED209 209
2940#define DUK_OP_UNUSED210 210
2941#define DUK_OP_UNUSED211 211
2942#define DUK_OP_UNUSED212 212
2943#define DUK_OP_UNUSED213 213
2944#define DUK_OP_UNUSED214 214
2945#define DUK_OP_UNUSED215 215
2946#define DUK_OP_UNUSED216 216
2947#define DUK_OP_UNUSED217 217
2948#define DUK_OP_UNUSED218 218
2949#define DUK_OP_UNUSED219 219
2950#define DUK_OP_UNUSED220 220
2951#define DUK_OP_UNUSED221 221
2952#define DUK_OP_UNUSED222 222
2953#define DUK_OP_UNUSED223 223
2954#define DUK_OP_UNUSED224 224
2955#define DUK_OP_UNUSED225 225
2956#define DUK_OP_UNUSED226 226
2957#define DUK_OP_UNUSED227 227
2958#define DUK_OP_UNUSED228 228
2959#define DUK_OP_UNUSED229 229
2960#define DUK_OP_UNUSED230 230
2961#define DUK_OP_UNUSED231 231
2962#define DUK_OP_UNUSED232 232
2963#define DUK_OP_UNUSED233 233
2964#define DUK_OP_UNUSED234 234
2965#define DUK_OP_UNUSED235 235
2966#define DUK_OP_UNUSED236 236
2967#define DUK_OP_UNUSED237 237
2968#define DUK_OP_UNUSED238 238
2969#define DUK_OP_UNUSED239 239
2970#define DUK_OP_UNUSED240 240
2971#define DUK_OP_UNUSED241 241
2972#define DUK_OP_UNUSED242 242
2973#define DUK_OP_UNUSED243 243
2974#define DUK_OP_UNUSED244 244
2975#define DUK_OP_UNUSED245 245
2976#define DUK_OP_UNUSED246 246
2977#define DUK_OP_UNUSED247 247
2978#define DUK_OP_UNUSED248 248
2979#define DUK_OP_UNUSED249 249
2980#define DUK_OP_UNUSED250 250
2981#define DUK_OP_UNUSED251 251
2982#define DUK_OP_UNUSED252 252
2983#define DUK_OP_UNUSED253 253
2984#define DUK_OP_UNUSED254 254
2985#define DUK_OP_UNUSED255 255
2986#define DUK_OP_NONE 256 /* dummy value used as marker (doesn't fit in 8-bit field) */
2987
2988/* XXX: Allocate flags from opcode field? Would take 16 opcode slots
2989 * but avoids shuffling in more cases. Maybe not worth it.
2990 */
2991/* DUK_OP_TRYCATCH flags in A */
2992#define DUK_BC_TRYCATCH_FLAG_HAVE_CATCH (1 << 0)
2993#define DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY (1 << 1)
2994#define DUK_BC_TRYCATCH_FLAG_CATCH_BINDING (1 << 2)
2995#define DUK_BC_TRYCATCH_FLAG_WITH_BINDING (1 << 3)
2996
2997/* DUK_OP_DECLVAR flags in A; bottom bits are reserved for propdesc flags (DUK_PROPDESC_FLAG_XXX) */
2998#define DUK_BC_DECLVAR_FLAG_UNDEF_VALUE (1 << 4) /* use 'undefined' for value automatically */
2999#define DUK_BC_DECLVAR_FLAG_FUNC_DECL (1 << 5) /* function declaration */
3000
3001/* Misc constants and helper macros. */
3002#define DUK_BC_LDINT_BIAS (1L << 15)
3003#define DUK_BC_LDINTX_SHIFT 16
3004#define DUK_BC_JUMP_BIAS (1L << 23)
3005
3006#endif /* DUK_JS_BYTECODE_H_INCLUDED */
3007/* #include duk_lexer.h */
3008/*
3009 * Lexer defines.
3010 */
3011
3012#if !defined(DUK_LEXER_H_INCLUDED)
3013#define DUK_LEXER_H_INCLUDED
3014
3015typedef void (*duk_re_range_callback)(void *user, duk_codepoint_t r1, duk_codepoint_t r2, duk_bool_t direct);
3016
3017/*
3018 * A token is interpreted as any possible production of InputElementDiv
3019 * and InputElementRegExp, see E5 Section 7 in its entirety. Note that
3020 * the E5 "Token" production does not cover all actual tokens of the
3021 * language (which is explicitly stated in the specification, Section 7.5).
3022 * Null and boolean literals are defined as part of both ReservedWord
3023 * (E5 Section 7.6.1) and Literal (E5 Section 7.8) productions. Here,
3024 * null and boolean values have literal tokens, and are not reserved
3025 * words.
3026 *
3027 * Decimal literal negative/positive sign is -not- part of DUK_TOK_NUMBER.
3028 * The number tokens always have a non-negative value. The unary minus
3029 * operator in "-1.0" is optimized during compilation to yield a single
3030 * negative constant.
3031 *
3032 * Token numbering is free except that reserved words are required to be
3033 * in a continuous range and in a particular order. See genstrings.py.
3034 */
3035
3036#define DUK_LEXER_INITCTX(ctx) duk_lexer_initctx((ctx))
3037
3038#define DUK_LEXER_SETPOINT(ctx,pt) duk_lexer_setpoint((ctx), (pt))
3039
3040#define DUK_LEXER_GETPOINT(ctx,pt) duk_lexer_getpoint((ctx), (pt))
3041
3042/* currently 6 characters of lookup are actually needed (duk_lexer.c) */
3043#define DUK_LEXER_WINDOW_SIZE 6
3044#if defined(DUK_USE_LEXER_SLIDING_WINDOW)
3045#define DUK_LEXER_BUFFER_SIZE 64
3046#endif
3047
3048#define DUK_TOK_MINVAL 0
3049
3050/* returned after EOF (infinite amount) */
3051#define DUK_TOK_EOF 0
3052
3053/* identifier names (E5 Section 7.6) */
3054#define DUK_TOK_IDENTIFIER 1
3055
3056/* reserved words: keywords */
3057#define DUK_TOK_START_RESERVED 2
3058#define DUK_TOK_BREAK 2
3059#define DUK_TOK_CASE 3
3060#define DUK_TOK_CATCH 4
3061#define DUK_TOK_CONTINUE 5
3062#define DUK_TOK_DEBUGGER 6
3063#define DUK_TOK_DEFAULT 7
3064#define DUK_TOK_DELETE 8
3065#define DUK_TOK_DO 9
3066#define DUK_TOK_ELSE 10
3067#define DUK_TOK_FINALLY 11
3068#define DUK_TOK_FOR 12
3069#define DUK_TOK_FUNCTION 13
3070#define DUK_TOK_IF 14
3071#define DUK_TOK_IN 15
3072#define DUK_TOK_INSTANCEOF 16
3073#define DUK_TOK_NEW 17
3074#define DUK_TOK_RETURN 18
3075#define DUK_TOK_SWITCH 19
3076#define DUK_TOK_THIS 20
3077#define DUK_TOK_THROW 21
3078#define DUK_TOK_TRY 22
3079#define DUK_TOK_TYPEOF 23
3080#define DUK_TOK_VAR 24
3081#define DUK_TOK_CONST 25
3082#define DUK_TOK_VOID 26
3083#define DUK_TOK_WHILE 27
3084#define DUK_TOK_WITH 28
3085
3086/* reserved words: future reserved words */
3087#define DUK_TOK_CLASS 29
3088#define DUK_TOK_ENUM 30
3089#define DUK_TOK_EXPORT 31
3090#define DUK_TOK_EXTENDS 32
3091#define DUK_TOK_IMPORT 33
3092#define DUK_TOK_SUPER 34
3093
3094/* "null", "true", and "false" are always reserved words.
3095 * Note that "get" and "set" are not!
3096 */
3097#define DUK_TOK_NULL 35
3098#define DUK_TOK_TRUE 36
3099#define DUK_TOK_FALSE 37
3100
3101/* reserved words: additional future reserved words in strict mode */
3102#define DUK_TOK_START_STRICT_RESERVED 38 /* inclusive */
3103#define DUK_TOK_IMPLEMENTS 38
3104#define DUK_TOK_INTERFACE 39
3105#define DUK_TOK_LET 40
3106#define DUK_TOK_PACKAGE 41
3107#define DUK_TOK_PRIVATE 42
3108#define DUK_TOK_PROTECTED 43
3109#define DUK_TOK_PUBLIC 44
3110#define DUK_TOK_STATIC 45
3111#define DUK_TOK_YIELD 46
3112
3113#define DUK_TOK_END_RESERVED 47 /* exclusive */
3114
3115/* "get" and "set" are tokens but NOT ReservedWords. They are currently
3116 * parsed and identifiers and these defines are actually now unused.
3117 */
3118#define DUK_TOK_GET 47
3119#define DUK_TOK_SET 48
3120
3121/* punctuators (unlike the spec, also includes "/" and "/=") */
3122#define DUK_TOK_LCURLY 49
3123#define DUK_TOK_RCURLY 50
3124#define DUK_TOK_LBRACKET 51
3125#define DUK_TOK_RBRACKET 52
3126#define DUK_TOK_LPAREN 53
3127#define DUK_TOK_RPAREN 54
3128#define DUK_TOK_PERIOD 55
3129#define DUK_TOK_SEMICOLON 56
3130#define DUK_TOK_COMMA 57
3131#define DUK_TOK_LT 58
3132#define DUK_TOK_GT 59
3133#define DUK_TOK_LE 60
3134#define DUK_TOK_GE 61
3135#define DUK_TOK_EQ 62
3136#define DUK_TOK_NEQ 63
3137#define DUK_TOK_SEQ 64
3138#define DUK_TOK_SNEQ 65
3139#define DUK_TOK_ADD 66
3140#define DUK_TOK_SUB 67
3141#define DUK_TOK_MUL 68
3142#define DUK_TOK_DIV 69
3143#define DUK_TOK_MOD 70
3144#define DUK_TOK_EXP 71
3145#define DUK_TOK_INCREMENT 72
3146#define DUK_TOK_DECREMENT 73
3147#define DUK_TOK_ALSHIFT 74 /* named "arithmetic" because result is signed */
3148#define DUK_TOK_ARSHIFT 75
3149#define DUK_TOK_RSHIFT 76
3150#define DUK_TOK_BAND 77
3151#define DUK_TOK_BOR 78
3152#define DUK_TOK_BXOR 79
3153#define DUK_TOK_LNOT 80
3154#define DUK_TOK_BNOT 81
3155#define DUK_TOK_LAND 82
3156#define DUK_TOK_LOR 83
3157#define DUK_TOK_QUESTION 84
3158#define DUK_TOK_COLON 85
3159#define DUK_TOK_EQUALSIGN 86
3160#define DUK_TOK_ADD_EQ 87
3161#define DUK_TOK_SUB_EQ 88
3162#define DUK_TOK_MUL_EQ 89
3163#define DUK_TOK_DIV_EQ 90
3164#define DUK_TOK_MOD_EQ 91
3165#define DUK_TOK_EXP_EQ 92
3166#define DUK_TOK_ALSHIFT_EQ 93
3167#define DUK_TOK_ARSHIFT_EQ 94
3168#define DUK_TOK_RSHIFT_EQ 95
3169#define DUK_TOK_BAND_EQ 96
3170#define DUK_TOK_BOR_EQ 97
3171#define DUK_TOK_BXOR_EQ 98
3172
3173/* literals (E5 Section 7.8), except null, true, false, which are treated
3174 * like reserved words (above).
3175 */
3176#define DUK_TOK_NUMBER 99
3177#define DUK_TOK_STRING 100
3178#define DUK_TOK_REGEXP 101
3179
3180#define DUK_TOK_MAXVAL 101 /* inclusive */
3181
3182/* Convert heap string index to a token (reserved words) */
3183#define DUK_STRIDX_TO_TOK(x) ((x) - DUK_STRIDX_START_RESERVED + DUK_TOK_START_RESERVED)
3184
3185/* Sanity check */
3186#if (DUK_TOK_MAXVAL > 255)
3187#error DUK_TOK_MAXVAL too large, code assumes it fits into 8 bits
3188#endif
3189
3190/* Sanity checks for string and token defines */
3191#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_BREAK) != DUK_TOK_BREAK)
3192#error mismatch in token defines
3193#endif
3194#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CASE) != DUK_TOK_CASE)
3195#error mismatch in token defines
3196#endif
3197#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CATCH) != DUK_TOK_CATCH)
3198#error mismatch in token defines
3199#endif
3200#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CONTINUE) != DUK_TOK_CONTINUE)
3201#error mismatch in token defines
3202#endif
3203#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DEBUGGER) != DUK_TOK_DEBUGGER)
3204#error mismatch in token defines
3205#endif
3206#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DEFAULT) != DUK_TOK_DEFAULT)
3207#error mismatch in token defines
3208#endif
3209#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DELETE) != DUK_TOK_DELETE)
3210#error mismatch in token defines
3211#endif
3212#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_DO) != DUK_TOK_DO)
3213#error mismatch in token defines
3214#endif
3215#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_ELSE) != DUK_TOK_ELSE)
3216#error mismatch in token defines
3217#endif
3218#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FINALLY) != DUK_TOK_FINALLY)
3219#error mismatch in token defines
3220#endif
3221#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FOR) != DUK_TOK_FOR)
3222#error mismatch in token defines
3223#endif
3224#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LC_FUNCTION) != DUK_TOK_FUNCTION)
3225#error mismatch in token defines
3226#endif
3227#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IF) != DUK_TOK_IF)
3228#error mismatch in token defines
3229#endif
3230#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IN) != DUK_TOK_IN)
3231#error mismatch in token defines
3232#endif
3233#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_INSTANCEOF) != DUK_TOK_INSTANCEOF)
3234#error mismatch in token defines
3235#endif
3236#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_NEW) != DUK_TOK_NEW)
3237#error mismatch in token defines
3238#endif
3239#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_RETURN) != DUK_TOK_RETURN)
3240#error mismatch in token defines
3241#endif
3242#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_SWITCH) != DUK_TOK_SWITCH)
3243#error mismatch in token defines
3244#endif
3245#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_THIS) != DUK_TOK_THIS)
3246#error mismatch in token defines
3247#endif
3248#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_THROW) != DUK_TOK_THROW)
3249#error mismatch in token defines
3250#endif
3251#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TRY) != DUK_TOK_TRY)
3252#error mismatch in token defines
3253#endif
3254#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TYPEOF) != DUK_TOK_TYPEOF)
3255#error mismatch in token defines
3256#endif
3257#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_VAR) != DUK_TOK_VAR)
3258#error mismatch in token defines
3259#endif
3260#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_VOID) != DUK_TOK_VOID)
3261#error mismatch in token defines
3262#endif
3263#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_WHILE) != DUK_TOK_WHILE)
3264#error mismatch in token defines
3265#endif
3266#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_WITH) != DUK_TOK_WITH)
3267#error mismatch in token defines
3268#endif
3269#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CLASS) != DUK_TOK_CLASS)
3270#error mismatch in token defines
3271#endif
3272#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_CONST) != DUK_TOK_CONST)
3273#error mismatch in token defines
3274#endif
3275#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_ENUM) != DUK_TOK_ENUM)
3276#error mismatch in token defines
3277#endif
3278#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_EXPORT) != DUK_TOK_EXPORT)
3279#error mismatch in token defines
3280#endif
3281#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_EXTENDS) != DUK_TOK_EXTENDS)
3282#error mismatch in token defines
3283#endif
3284#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IMPORT) != DUK_TOK_IMPORT)
3285#error mismatch in token defines
3286#endif
3287#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_SUPER) != DUK_TOK_SUPER)
3288#error mismatch in token defines
3289#endif
3290#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LC_NULL) != DUK_TOK_NULL)
3291#error mismatch in token defines
3292#endif
3293#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_TRUE) != DUK_TOK_TRUE)
3294#error mismatch in token defines
3295#endif
3296#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_FALSE) != DUK_TOK_FALSE)
3297#error mismatch in token defines
3298#endif
3299#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_IMPLEMENTS) != DUK_TOK_IMPLEMENTS)
3300#error mismatch in token defines
3301#endif
3302#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_INTERFACE) != DUK_TOK_INTERFACE)
3303#error mismatch in token defines
3304#endif
3305#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_LET) != DUK_TOK_LET)
3306#error mismatch in token defines
3307#endif
3308#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PACKAGE) != DUK_TOK_PACKAGE)
3309#error mismatch in token defines
3310#endif
3311#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PRIVATE) != DUK_TOK_PRIVATE)
3312#error mismatch in token defines
3313#endif
3314#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PROTECTED) != DUK_TOK_PROTECTED)
3315#error mismatch in token defines
3316#endif
3317#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_PUBLIC) != DUK_TOK_PUBLIC)
3318#error mismatch in token defines
3319#endif
3320#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_STATIC) != DUK_TOK_STATIC)
3321#error mismatch in token defines
3322#endif
3323#if (DUK_STRIDX_TO_TOK(DUK_STRIDX_YIELD) != DUK_TOK_YIELD)
3324#error mismatch in token defines
3325#endif
3326
3327/* Regexp tokens */
3328#define DUK_RETOK_EOF 0
3329#define DUK_RETOK_DISJUNCTION 1
3330#define DUK_RETOK_QUANTIFIER 2
3331#define DUK_RETOK_ASSERT_START 3
3332#define DUK_RETOK_ASSERT_END 4
3333#define DUK_RETOK_ASSERT_WORD_BOUNDARY 5
3334#define DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY 6
3335#define DUK_RETOK_ASSERT_START_POS_LOOKAHEAD 7
3336#define DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD 8
3337#define DUK_RETOK_ATOM_PERIOD 9
3338#define DUK_RETOK_ATOM_CHAR 10
3339#define DUK_RETOK_ATOM_DIGIT 11 /* assumptions in regexp compiler */
3340#define DUK_RETOK_ATOM_NOT_DIGIT 12 /* -""- */
3341#define DUK_RETOK_ATOM_WHITE 13 /* -""- */
3342#define DUK_RETOK_ATOM_NOT_WHITE 14 /* -""- */
3343#define DUK_RETOK_ATOM_WORD_CHAR 15 /* -""- */
3344#define DUK_RETOK_ATOM_NOT_WORD_CHAR 16 /* -""- */
3345#define DUK_RETOK_ATOM_BACKREFERENCE 17
3346#define DUK_RETOK_ATOM_START_CAPTURE_GROUP 18
3347#define DUK_RETOK_ATOM_START_NONCAPTURE_GROUP 19
3348#define DUK_RETOK_ATOM_START_CHARCLASS 20
3349#define DUK_RETOK_ATOM_START_CHARCLASS_INVERTED 21
3350#define DUK_RETOK_ATOM_END_GROUP 22
3351
3352/* Constants for duk_lexer_ctx.buf. */
3353#define DUK_LEXER_TEMP_BUF_LIMIT 256
3354
3355/* A token value. Can be memcpy()'d, but note that slot1/slot2 values are on the valstack.
3356 * Some fields (like num, str1, str2) are only valid for specific token types and may have
3357 * stale values otherwise.
3358 */
3360 duk_small_int_t t; /* token type (with reserved word identification) */
3361 duk_small_int_t t_nores; /* token type (with reserved words as DUK_TOK_IDENTIFER) */
3362 duk_double_t num; /* numeric value of token */
3363 duk_hstring *str1; /* string 1 of token (borrowed, stored to ctx->slot1_idx) */
3364 duk_hstring *str2; /* string 2 of token (borrowed, stored to ctx->slot2_idx) */
3365 duk_size_t start_offset; /* start byte offset of token in lexer input */
3366 duk_int_t start_line; /* start line of token (first char) */
3367 duk_int_t num_escapes; /* number of escapes and line continuations (for directive prologue) */
3368 duk_bool_t lineterm; /* token was preceded by a lineterm */
3369 duk_bool_t allow_auto_semi; /* token allows automatic semicolon insertion (eof or preceded by newline) */
3370};
3371
3372#define DUK_RE_QUANTIFIER_INFINITE ((duk_uint32_t) 0xffffffffUL)
3373
3374/* A regexp token value. */
3376 duk_small_int_t t; /* token type */
3377 duk_small_int_t greedy;
3378 duk_uint_fast32_t num; /* numeric value (character, count) */
3379 duk_uint_fast32_t qmin;
3380 duk_uint_fast32_t qmax;
3381};
3382
3383/* A structure for 'snapshotting' a point for rewinding */
3385 duk_size_t offset;
3386 duk_int_t line;
3387};
3388
3389/* Lexer codepoint with additional info like offset/line number */
3391 duk_codepoint_t codepoint;
3392 duk_size_t offset;
3393 duk_int_t line;
3394};
3395
3396/* Lexer context. Same context is used for Ecmascript and Regexp parsing. */
3398#if defined(DUK_USE_LEXER_SLIDING_WINDOW)
3399 duk_lexer_codepoint *window; /* unicode code points, window[0] is always next, points to 'buffer' */
3400 duk_lexer_codepoint buffer[DUK_LEXER_BUFFER_SIZE];
3401#else
3402 duk_lexer_codepoint window[DUK_LEXER_WINDOW_SIZE]; /* unicode code points, window[0] is always next */
3403#endif
3404
3405 duk_hthread *thr; /* thread; minimizes argument passing */
3406
3407 const duk_uint8_t *input; /* input string (may be a user pointer) */
3408 duk_size_t input_length; /* input byte length */
3409 duk_size_t input_offset; /* input offset for window leading edge (not window[0]) */
3410 duk_int_t input_line; /* input linenumber at input_offset (not window[0]), init to 1 */
3411
3412 duk_idx_t slot1_idx; /* valstack slot for 1st token value */
3413 duk_idx_t slot2_idx; /* valstack slot for 2nd token value */
3414 duk_idx_t buf_idx; /* valstack slot for temp buffer */
3415 duk_hbuffer_dynamic *buf; /* temp accumulation buffer */
3416 duk_bufwriter_ctx bw; /* bufwriter for temp accumulation */
3417
3418 duk_int_t token_count; /* number of tokens parsed */
3419 duk_int_t token_limit; /* maximum token count before error (sanity backstop) */
3420};
3421
3422/*
3423 * Prototypes
3424 */
3425
3426DUK_INTERNAL_DECL void duk_lexer_initctx(duk_lexer_ctx *lex_ctx);
3427
3428DUK_INTERNAL_DECL void duk_lexer_getpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt);
3429DUK_INTERNAL_DECL void duk_lexer_setpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt);
3430
3431DUK_INTERNAL_DECL
3432void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
3433 duk_token *out_token,
3434 duk_bool_t strict_mode,
3435 duk_bool_t regexp_mode);
3436#if defined(DUK_USE_REGEXP_SUPPORT)
3437DUK_INTERNAL_DECL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token *out_token);
3438DUK_INTERNAL_DECL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range_callback gen_range, void *userdata);
3439#endif /* DUK_USE_REGEXP_SUPPORT */
3440
3441#endif /* DUK_LEXER_H_INCLUDED */
3442/* #include duk_js_compiler.h */
3443/*
3444 * Ecmascript compiler.
3445 */
3446
3447#if !defined(DUK_JS_COMPILER_H_INCLUDED)
3448#define DUK_JS_COMPILER_H_INCLUDED
3449
3450/* ecmascript compiler limits */
3451#define DUK_COMPILER_TOKEN_LIMIT 100000000L /* 1e8: protects against deeply nested inner functions */
3452
3453/* maximum loopcount for peephole optimization */
3454#define DUK_COMPILER_PEEPHOLE_MAXITER 3
3455
3456/* maximum bytecode length in instructions */
3457#define DUK_COMPILER_MAX_BYTECODE_LENGTH (256L * 1024L * 1024L) /* 1 GB */
3458
3459/*
3460 * Compiler intermediate values
3461 *
3462 * Intermediate values describe either plain values (e.g. strings or
3463 * numbers) or binary operations which have not yet been coerced into
3464 * either a left-hand-side or right-hand-side role (e.g. object property).
3465 */
3466
3467#define DUK_IVAL_NONE 0 /* no value */
3468#define DUK_IVAL_PLAIN 1 /* register, constant, or value */
3469#define DUK_IVAL_ARITH 2 /* binary arithmetic; DUK_OP_ADD, DUK_OP_EQ, other binary ops */
3470#define DUK_IVAL_PROP 3 /* property access */
3471#define DUK_IVAL_VAR 4 /* variable access */
3472
3473#define DUK_ISPEC_NONE 0 /* no value */
3474#define DUK_ISPEC_VALUE 1 /* value resides in 'valstack_idx' */
3475#define DUK_ISPEC_REGCONST 2 /* value resides in a register or constant */
3476
3477/* Bit mask which indicates that a regconst is a constant instead of a register.
3478 * Chosen so that when a regconst is cast to duk_int32_t, all consts are
3479 * negative values.
3480 */
3481#define DUK_REGCONST_CONST_MARKER 0x80000000UL
3482
3483/* type to represent a reg/const reference during compilation */
3484typedef duk_uint32_t duk_regconst_t;
3485
3486/* type to represent a straight register reference, with <0 indicating none */
3487typedef duk_int32_t duk_reg_t;
3488
3489typedef struct {
3490 duk_small_uint_t t; /* DUK_ISPEC_XXX */
3491 duk_regconst_t regconst;
3492 duk_idx_t valstack_idx; /* always set; points to a reserved valstack slot */
3493} duk_ispec;
3494
3495typedef struct {
3496 /*
3497 * PLAIN: x1
3498 * ARITH: x1 <op> x2
3499 * PROP: x1.x2
3500 * VAR: x1 (name)
3501 */
3502
3503 /* XXX: can be optimized for smaller footprint esp. on 32-bit environments */
3504 duk_small_uint_t t; /* DUK_IVAL_XXX */
3505 duk_small_uint_t op; /* bytecode opcode for binary ops */
3506 duk_ispec x1;
3507 duk_ispec x2;
3508} duk_ivalue;
3509
3510/*
3511 * Bytecode instruction representation during compilation
3512 *
3513 * Contains the actual instruction and (optionally) debug info.
3514 */
3515
3517 duk_instr_t ins;
3518#if defined(DUK_USE_PC2LINE)
3519 duk_uint32_t line;
3520#endif
3521};
3522
3523/*
3524 * Compiler state
3525 */
3526
3527#define DUK_LABEL_FLAG_ALLOW_BREAK (1 << 0)
3528#define DUK_LABEL_FLAG_ALLOW_CONTINUE (1 << 1)
3529
3530#define DUK_DECL_TYPE_VAR 0
3531#define DUK_DECL_TYPE_FUNC 1
3532
3533/* XXX: optimize to 16 bytes */
3534typedef struct {
3535 duk_small_uint_t flags;
3536 duk_int_t label_id; /* numeric label_id (-1 reserved as marker) */
3537 duk_hstring *h_label; /* borrowed label name */
3538 duk_int_t catch_depth; /* catch depth at point of definition */
3539 duk_int_t pc_label; /* pc of label statement:
3540 * pc+1: break jump site
3541 * pc+2: continue jump site
3542 */
3543
3544 /* Fast jumps (which avoid longjmp) jump directly to the jump sites
3545 * which are always known even while the iteration/switch statement
3546 * is still being parsed. A final peephole pass "straightens out"
3547 * the jumps.
3548 */
3550
3551/* Compiling state of one function, eventually converted to duk_hcompfunc */
3553 /* These pointers are at the start of the struct so that they pack
3554 * nicely. Mixing pointers and integer values is bad on some
3555 * platforms (e.g. if int is 32 bits and pointers are 64 bits).
3556 */
3557
3558 duk_bufwriter_ctx bw_code; /* bufwriter for code */
3559
3560 duk_hstring *h_name; /* function name (borrowed reference), ends up in _name */
3561 /* h_code: held in bw_code */
3562 duk_hobject *h_consts; /* array */
3563 duk_hobject *h_funcs; /* array of function templates: [func1, offset1, line1, func2, offset2, line2]
3564 * offset/line points to closing brace to allow skipping on pass 2
3565 */
3566 duk_hobject *h_decls; /* array of declarations: [ name1, val1, name2, val2, ... ]
3567 * valN = (typeN) | (fnum << 8), where fnum is inner func number (0 for vars)
3568 * record function and variable declarations in pass 1
3569 */
3570 duk_hobject *h_labelnames; /* array of active label names */
3571 duk_hbuffer_dynamic *h_labelinfos; /* C array of duk_labelinfo */
3572 duk_hobject *h_argnames; /* array of formal argument names (-> _Formals) */
3573 duk_hobject *h_varmap; /* variable map for pass 2 (identifier -> register number or null (unmapped)) */
3574
3575 /* Value stack indices for tracking objects. */
3576 /* code_idx: not needed */
3577 duk_idx_t consts_idx;
3578 duk_idx_t funcs_idx;
3579 duk_idx_t decls_idx;
3580 duk_idx_t labelnames_idx;
3581 duk_idx_t labelinfos_idx;
3582 duk_idx_t argnames_idx;
3583 duk_idx_t varmap_idx;
3584
3585 /* Temp reg handling. */
3586 duk_reg_t temp_first; /* first register that is a temporary (below: variables) */
3587 duk_reg_t temp_next; /* next temporary register to allocate */
3588 duk_reg_t temp_max; /* highest value of temp_reg (temp_max - 1 is highest used reg) */
3589
3590 /* Shuffle registers if large number of regs/consts. */
3591 duk_reg_t shuffle1;
3592 duk_reg_t shuffle2;
3593 duk_reg_t shuffle3;
3594
3595 /* Stats for current expression being parsed. */
3596 duk_int_t nud_count;
3597 duk_int_t led_count;
3598 duk_int_t paren_level; /* parenthesis count, 0 = top level */
3599 duk_bool_t expr_lhs; /* expression is left-hand-side compatible */
3600 duk_bool_t allow_in; /* current paren level allows 'in' token */
3601
3602 /* Misc. */
3603 duk_int_t stmt_next; /* statement id allocation (running counter) */
3604 duk_int_t label_next; /* label id allocation (running counter) */
3605 duk_int_t catch_depth; /* catch stack depth */
3606 duk_int_t with_depth; /* with stack depth (affects identifier lookups) */
3607 duk_int_t fnum_next; /* inner function numbering */
3608 duk_int_t num_formals; /* number of formal arguments */
3609 duk_reg_t reg_stmt_value; /* register for writing value of 'non-empty' statements (global or eval code), -1 is marker */
3610#if defined(DUK_USE_DEBUGGER_SUPPORT)
3611 duk_int_t min_line; /* XXX: typing (duk_hcompfunc has duk_uint32_t) */
3612 duk_int_t max_line;
3613#endif
3614
3615 /* Status booleans. */
3616 duk_uint8_t is_function; /* is an actual function (not global/eval code) */
3617 duk_uint8_t is_eval; /* is eval code */
3618 duk_uint8_t is_global; /* is global code */
3619 duk_uint8_t is_namebinding; /* needs a name binding */
3620 duk_uint8_t is_constructable; /* result is constructable */
3621 duk_uint8_t is_setget; /* is a setter/getter */
3622 duk_uint8_t is_strict; /* function is strict */
3623 duk_uint8_t is_notail; /* function must not be tail called */
3624 duk_uint8_t in_directive_prologue; /* parsing in "directive prologue", recognize directives */
3625 duk_uint8_t in_scanning; /* parsing in "scanning" phase (first pass) */
3626 duk_uint8_t may_direct_eval; /* function may call direct eval */
3627 duk_uint8_t id_access_arguments; /* function refers to 'arguments' identifier */
3628 duk_uint8_t id_access_slow; /* function makes one or more slow path accesses that won't match own static variables */
3629 duk_uint8_t id_access_slow_own; /* function makes one or more slow path accesses that may match own static variables */
3630 duk_uint8_t is_arguments_shadowed; /* argument/function declaration shadows 'arguments' */
3631 duk_uint8_t needs_shuffle; /* function needs shuffle registers */
3632 duk_uint8_t reject_regexp_in_adv; /* reject RegExp literal on next advance() call; needed for handling IdentifierName productions */
3633};
3634
3636 duk_hthread *thr;
3637
3638 /* filename being compiled (ends up in functions' '_filename' property) */
3639 duk_hstring *h_filename; /* borrowed reference */
3640
3641 /* lexing (tokenization) state (contains two valstack slot indices) */
3642 duk_lexer_ctx lex;
3643
3644 /* current and previous token for parsing */
3645 duk_token prev_token;
3646 duk_token curr_token;
3647 duk_idx_t tok11_idx; /* curr_token slot1 (matches 'lex' slot1_idx) */
3648 duk_idx_t tok12_idx; /* curr_token slot2 (matches 'lex' slot2_idx) */
3649 duk_idx_t tok21_idx; /* prev_token slot1 */
3650 duk_idx_t tok22_idx; /* prev_token slot2 */
3651
3652 /* recursion limit */
3653 duk_int_t recursion_depth;
3654 duk_int_t recursion_limit;
3655
3656 /* code emission temporary */
3657 duk_int_t emit_jumpslot_pc;
3658
3659 /* current function being compiled (embedded instead of pointer for more compact access) */
3660 duk_compiler_func curr_func;
3661};
3662
3663/*
3664 * Prototypes
3665 */
3666
3667#define DUK_JS_COMPILE_FLAG_EVAL (1 << 0) /* source is eval code (not global) */
3668#define DUK_JS_COMPILE_FLAG_STRICT (1 << 1) /* strict outer context */
3669#define DUK_JS_COMPILE_FLAG_FUNCEXPR (1 << 2) /* source is a function expression (used for Function constructor) */
3670
3671DUK_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);
3672
3673#endif /* DUK_JS_COMPILER_H_INCLUDED */
3674/* #include duk_regexp.h */
3675/*
3676 * Regular expression structs, constants, and bytecode defines.
3677 */
3678
3679#if !defined(DUK_REGEXP_H_INCLUDED)
3680#define DUK_REGEXP_H_INCLUDED
3681
3682/* maximum bytecode copies for {n,m} quantifiers */
3683#define DUK_RE_MAX_ATOM_COPIES 1000
3684
3685/* regexp compilation limits */
3686#define DUK_RE_COMPILE_TOKEN_LIMIT 100000000L /* 1e8 */
3687
3688/* regexp execution limits */
3689#define DUK_RE_EXECUTE_STEPS_LIMIT 1000000000L /* 1e9 */
3690
3691/* regexp opcodes */
3692#define DUK_REOP_MATCH 1
3693#define DUK_REOP_CHAR 2
3694#define DUK_REOP_PERIOD 3
3695#define DUK_REOP_RANGES 4
3696#define DUK_REOP_INVRANGES 5
3697#define DUK_REOP_JUMP 6
3698#define DUK_REOP_SPLIT1 7
3699#define DUK_REOP_SPLIT2 8
3700#define DUK_REOP_SQMINIMAL 9
3701#define DUK_REOP_SQGREEDY 10
3702#define DUK_REOP_SAVE 11
3703#define DUK_REOP_WIPERANGE 12
3704#define DUK_REOP_LOOKPOS 13
3705#define DUK_REOP_LOOKNEG 14
3706#define DUK_REOP_BACKREFERENCE 15
3707#define DUK_REOP_ASSERT_START 16
3708#define DUK_REOP_ASSERT_END 17
3709#define DUK_REOP_ASSERT_WORD_BOUNDARY 18
3710#define DUK_REOP_ASSERT_NOT_WORD_BOUNDARY 19
3711
3712/* flags */
3713#define DUK_RE_FLAG_GLOBAL (1 << 0)
3714#define DUK_RE_FLAG_IGNORE_CASE (1 << 1)
3715#define DUK_RE_FLAG_MULTILINE (1 << 2)
3716
3718 duk_hthread *thr;
3719
3720 duk_uint32_t re_flags;
3721 const duk_uint8_t *input;
3722 const duk_uint8_t *input_end;
3723 const duk_uint8_t *bytecode;
3724 const duk_uint8_t *bytecode_end;
3725 const duk_uint8_t **saved; /* allocated from valstack (fixed buffer) */
3726 duk_uint32_t nsaved;
3727 duk_uint32_t recursion_depth;
3728 duk_uint32_t recursion_limit;
3729 duk_uint32_t steps_count;
3730 duk_uint32_t steps_limit;
3731};
3732
3734 duk_hthread *thr;
3735
3736 duk_uint32_t re_flags;
3737 duk_lexer_ctx lex;
3738 duk_re_token curr_token;
3740 duk_uint32_t captures; /* highest capture number emitted so far (used as: ++captures) */
3741 duk_uint32_t highest_backref;
3742 duk_uint32_t recursion_depth;
3743 duk_uint32_t recursion_limit;
3744 duk_uint32_t nranges; /* internal temporary value, used for char classes */
3745};
3746
3747/*
3748 * Prototypes
3749 */
3750
3751#if defined(DUK_USE_REGEXP_SUPPORT)
3752DUK_INTERNAL_DECL void duk_regexp_compile(duk_hthread *thr);
3753DUK_INTERNAL_DECL void duk_regexp_create_instance(duk_hthread *thr);
3754DUK_INTERNAL_DECL void duk_regexp_match(duk_hthread *thr);
3755DUK_INTERNAL_DECL void duk_regexp_match_force_global(duk_hthread *thr); /* hacky helper for String.prototype.split() */
3756#endif
3757
3758#endif /* DUK_REGEXP_H_INCLUDED */
3759/* #include duk_heaphdr.h */
3760/*
3761 * Heap header definition and assorted macros, including ref counting.
3762 * Access all fields through the accessor macros.
3763 */
3764
3765#if !defined(DUK_HEAPHDR_H_INCLUDED)
3766#define DUK_HEAPHDR_H_INCLUDED
3767
3768/*
3769 * Common heap header
3770 *
3771 * All heap objects share the same flags and refcount fields. Objects other
3772 * than strings also need to have a single or double linked list pointers
3773 * for insertion into the "heap allocated" list. Strings are held in the
3774 * heap-wide string table so they don't need link pointers.
3775 *
3776 * Technically, 'h_refcount' must be wide enough to guarantee that it cannot
3777 * wrap (otherwise objects might be freed incorrectly after wrapping). This
3778 * means essentially that the refcount field must be as wide as data pointers.
3779 * On 64-bit platforms this means that the refcount needs to be 64 bits even
3780 * if an 'int' is 32 bits. This is a bit unfortunate, and compromising on
3781 * this might be reasonable in the future.
3782 *
3783 * Heap header size on 32-bit platforms: 8 bytes without reference counting,
3784 * 16 bytes with reference counting.
3785 */
3786
3788 duk_uint32_t h_flags;
3789
3790#if defined(DUK_USE_REFERENCE_COUNTING)
3791#if defined(DUK_USE_REFCOUNT16)
3792 duk_uint16_t h_refcount16;
3793#else
3794 duk_size_t h_refcount;
3795#endif
3796#endif
3797
3798#if defined(DUK_USE_HEAPPTR16)
3799 duk_uint16_t h_next16;
3800#else
3801 duk_heaphdr *h_next;
3802#endif
3803
3804#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
3805 /* refcounting requires direct heap frees, which in turn requires a dual linked heap */
3806#if defined(DUK_USE_HEAPPTR16)
3807 duk_uint16_t h_prev16;
3808#else
3809 duk_heaphdr *h_prev;
3810#endif
3811#endif
3812
3813 /* When DUK_USE_HEAPPTR16 (and DUK_USE_REFCOUNT16) is in use, the
3814 * struct won't align nicely to 4 bytes. This 16-bit extra field
3815 * is added to make the alignment clean; the field can be used by
3816 * heap objects when 16-bit packing is used. This field is now
3817 * conditional to DUK_USE_HEAPPTR16 only, but it is intended to be
3818 * used with DUK_USE_REFCOUNT16 and DUK_USE_DOUBLE_LINKED_HEAP;
3819 * this only matter to low memory environments anyway.
3820 */
3821#if defined(DUK_USE_HEAPPTR16)
3822 duk_uint16_t h_extra16;
3823#endif
3824};
3825
3827 /* 16 bits would be enough for shared heaphdr flags and duk_hstring
3828 * flags. The initial parts of duk_heaphdr_string and duk_heaphdr
3829 * must match so changing the flags field size here would be quite
3830 * awkward. However, to minimize struct size, we can pack at least
3831 * 16 bits of duk_hstring data into the flags field.
3832 */
3833 duk_uint32_t h_flags;
3834
3835#if defined(DUK_USE_REFERENCE_COUNTING)
3836#if defined(DUK_USE_REFCOUNT16)
3837 duk_uint16_t h_refcount16;
3838 duk_uint16_t h_strextra16; /* round out to 8 bytes */
3839#else
3840 duk_size_t h_refcount;
3841#endif
3842#else
3843 duk_uint16_t h_strextra16;
3844#endif
3845};
3846
3847#define DUK_HEAPHDR_FLAGS_TYPE_MASK 0x00000003UL
3848#define DUK_HEAPHDR_FLAGS_FLAG_MASK (~DUK_HEAPHDR_FLAGS_TYPE_MASK)
3849
3850 /* 2 bits for heap type */
3851#define DUK_HEAPHDR_FLAGS_HEAP_START 2 /* 5 heap flags */
3852#define DUK_HEAPHDR_FLAGS_USER_START 7 /* 25 user flags */
3853
3854#define DUK_HEAPHDR_HEAP_FLAG_NUMBER(n) (DUK_HEAPHDR_FLAGS_HEAP_START + (n))
3855#define DUK_HEAPHDR_USER_FLAG_NUMBER(n) (DUK_HEAPHDR_FLAGS_USER_START + (n))
3856#define DUK_HEAPHDR_HEAP_FLAG(n) (1UL << (DUK_HEAPHDR_FLAGS_HEAP_START + (n)))
3857#define DUK_HEAPHDR_USER_FLAG(n) (1UL << (DUK_HEAPHDR_FLAGS_USER_START + (n)))
3858
3859#define DUK_HEAPHDR_FLAG_REACHABLE DUK_HEAPHDR_HEAP_FLAG(0) /* mark-and-sweep: reachable */
3860#define DUK_HEAPHDR_FLAG_TEMPROOT DUK_HEAPHDR_HEAP_FLAG(1) /* mark-and-sweep: children not processed */
3861#define DUK_HEAPHDR_FLAG_FINALIZABLE DUK_HEAPHDR_HEAP_FLAG(2) /* mark-and-sweep: finalizable (on current pass) */
3862#define DUK_HEAPHDR_FLAG_FINALIZED DUK_HEAPHDR_HEAP_FLAG(3) /* mark-and-sweep: finalized (on previous pass) */
3863#define DUK_HEAPHDR_FLAG_READONLY DUK_HEAPHDR_HEAP_FLAG(4) /* read-only object, in code section */
3864
3865#define DUK_HTYPE_MIN 0
3866#define DUK_HTYPE_STRING 0
3867#define DUK_HTYPE_OBJECT 1
3868#define DUK_HTYPE_BUFFER 2
3869#define DUK_HTYPE_MAX 2
3870
3871#if defined(DUK_USE_HEAPPTR16)
3872#define DUK_HEAPHDR_GET_NEXT(heap,h) \
3873 ((duk_heaphdr *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->h_next16))
3874#define DUK_HEAPHDR_SET_NEXT(heap,h,val) do { \
3875 (h)->h_next16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) val); \
3876 } while (0)
3877#else
3878#define DUK_HEAPHDR_GET_NEXT(heap,h) ((h)->h_next)
3879#define DUK_HEAPHDR_SET_NEXT(heap,h,val) do { \
3880 (h)->h_next = (val); \
3881 } while (0)
3882#endif
3883
3884#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
3885#if defined(DUK_USE_HEAPPTR16)
3886#define DUK_HEAPHDR_GET_PREV(heap,h) \
3887 ((duk_heaphdr *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->h_prev16))
3888#define DUK_HEAPHDR_SET_PREV(heap,h,val) do { \
3889 (h)->h_prev16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (val)); \
3890 } while (0)
3891#else
3892#define DUK_HEAPHDR_GET_PREV(heap,h) ((h)->h_prev)
3893#define DUK_HEAPHDR_SET_PREV(heap,h,val) do { \
3894 (h)->h_prev = (val); \
3895 } while (0)
3896#endif
3897#endif
3898
3899#if defined(DUK_USE_REFERENCE_COUNTING)
3900#if defined(DUK_USE_REFCOUNT16)
3901#define DUK_HEAPHDR_GET_REFCOUNT(h) ((h)->h_refcount16)
3902#define DUK_HEAPHDR_SET_REFCOUNT(h,val) do { \
3903 (h)->h_refcount16 = (val); \
3904 } while (0)
3905#define DUK_HEAPHDR_PREINC_REFCOUNT(h) (++(h)->h_refcount16) /* result: updated refcount */
3906#define DUK_HEAPHDR_PREDEC_REFCOUNT(h) (--(h)->h_refcount16) /* result: updated refcount */
3907#else
3908#define DUK_HEAPHDR_GET_REFCOUNT(h) ((h)->h_refcount)
3909#define DUK_HEAPHDR_SET_REFCOUNT(h,val) do { \
3910 (h)->h_refcount = (val); \
3911 } while (0)
3912#define DUK_HEAPHDR_PREINC_REFCOUNT(h) (++(h)->h_refcount) /* result: updated refcount */
3913#define DUK_HEAPHDR_PREDEC_REFCOUNT(h) (--(h)->h_refcount) /* result: updated refcount */
3914#endif
3915#else
3916/* refcount macros not defined without refcounting, caller must #if defined() now */
3917#endif /* DUK_USE_REFERENCE_COUNTING */
3918
3919/*
3920 * Note: type is treated as a field separate from flags, so some masking is
3921 * involved in the macros below.
3922 */
3923
3924#define DUK_HEAPHDR_GET_FLAGS_RAW(h) ((h)->h_flags)
3925#define DUK_HEAPHDR_SET_FLAGS_RAW(h,val) do { \
3926 (h)->h_flags = (val); } \
3927 }
3928#define DUK_HEAPHDR_GET_FLAGS(h) ((h)->h_flags & DUK_HEAPHDR_FLAGS_FLAG_MASK)
3929#define DUK_HEAPHDR_SET_FLAGS(h,val) do { \
3930 (h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) | (val); \
3931 } while (0)
3932#define DUK_HEAPHDR_GET_TYPE(h) ((h)->h_flags & DUK_HEAPHDR_FLAGS_TYPE_MASK)
3933#define DUK_HEAPHDR_SET_TYPE(h,val) do { \
3934 (h)->h_flags = ((h)->h_flags & ~(DUK_HEAPHDR_FLAGS_TYPE_MASK)) | (val); \
3935 } while (0)
3936
3937/* Comparison for type >= DUK_HTYPE_MIN skipped; because DUK_HTYPE_MIN is zero
3938 * and the comparison is unsigned, it's always true and generates warnings.
3939 */
3940#define DUK_HEAPHDR_HTYPE_VALID(h) ( \
3941 DUK_HEAPHDR_GET_TYPE((h)) <= DUK_HTYPE_MAX \
3942 )
3943
3944#define DUK_HEAPHDR_SET_TYPE_AND_FLAGS(h,tval,fval) do { \
3945 (h)->h_flags = ((tval) & DUK_HEAPHDR_FLAGS_TYPE_MASK) | \
3946 ((fval) & DUK_HEAPHDR_FLAGS_FLAG_MASK); \
3947 } while (0)
3948
3949#define DUK_HEAPHDR_SET_FLAG_BITS(h,bits) do { \
3950 DUK_ASSERT(((bits) & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) == 0); \
3951 (h)->h_flags |= (bits); \
3952 } while (0)
3953
3954#define DUK_HEAPHDR_CLEAR_FLAG_BITS(h,bits) do { \
3955 DUK_ASSERT(((bits) & ~(DUK_HEAPHDR_FLAGS_FLAG_MASK)) == 0); \
3956 (h)->h_flags &= ~((bits)); \
3957 } while (0)
3958
3959#define DUK_HEAPHDR_CHECK_FLAG_BITS(h,bits) (((h)->h_flags & (bits)) != 0)
3960
3961#define DUK_HEAPHDR_SET_REACHABLE(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE)
3962#define DUK_HEAPHDR_CLEAR_REACHABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE)
3963#define DUK_HEAPHDR_HAS_REACHABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_REACHABLE)
3964
3965#define DUK_HEAPHDR_SET_TEMPROOT(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT)
3966#define DUK_HEAPHDR_CLEAR_TEMPROOT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT)
3967#define DUK_HEAPHDR_HAS_TEMPROOT(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_TEMPROOT)
3968
3969#define DUK_HEAPHDR_SET_FINALIZABLE(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE)
3970#define DUK_HEAPHDR_CLEAR_FINALIZABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE)
3971#define DUK_HEAPHDR_HAS_FINALIZABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZABLE)
3972
3973#define DUK_HEAPHDR_SET_FINALIZED(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED)
3974#define DUK_HEAPHDR_CLEAR_FINALIZED(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED)
3975#define DUK_HEAPHDR_HAS_FINALIZED(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_FINALIZED)
3976
3977#define DUK_HEAPHDR_SET_READONLY(h) DUK_HEAPHDR_SET_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY)
3978#define DUK_HEAPHDR_CLEAR_READONLY(h) DUK_HEAPHDR_CLEAR_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY)
3979#define DUK_HEAPHDR_HAS_READONLY(h) DUK_HEAPHDR_CHECK_FLAG_BITS((h),DUK_HEAPHDR_FLAG_READONLY)
3980
3981/* get or set a range of flags; m=first bit number, n=number of bits */
3982#define DUK_HEAPHDR_GET_FLAG_RANGE(h,m,n) (((h)->h_flags >> (m)) & ((1UL << (n)) - 1UL))
3983
3984#define DUK_HEAPHDR_SET_FLAG_RANGE(h,m,n,v) do { \
3985 (h)->h_flags = \
3986 ((h)->h_flags & (~(((1UL << (n)) - 1UL) << (m)))) \
3987 | ((v) << (m)); \
3988 } while (0)
3989
3990/* init pointer fields to null */
3991#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
3992#define DUK_HEAPHDR_INIT_NULLS(h) do { \
3993 DUK_HEAPHDR_SET_NEXT((h), (void *) NULL); \
3994 DUK_HEAPHDR_SET_PREV((h), (void *) NULL); \
3995 } while (0)
3996#else
3997#define DUK_HEAPHDR_INIT_NULLS(h) do { \
3998 DUK_HEAPHDR_SET_NEXT((h), (void *) NULL); \
3999 } while (0)
4000#endif
4001
4002#define DUK_HEAPHDR_STRING_INIT_NULLS(h) /* currently nop */
4003
4004/*
4005 * Type tests
4006 */
4007
4008#define DUK_HEAPHDR_IS_OBJECT(h) \
4009 (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_OBJECT)
4010#define DUK_HEAPHDR_IS_STRING(h) \
4011 (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_STRING)
4012#define DUK_HEAPHDR_IS_BUFFER(h) \
4013 (DUK_HEAPHDR_GET_TYPE((h)) == DUK_HTYPE_BUFFER)
4014
4015/*
4016 * Assert helpers
4017 */
4018
4019/* Check that prev/next links are consistent: if e.g. h->prev is != NULL,
4020 * h->prev->next should point back to h.
4021 */
4022#if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_ASSERTIONS)
4023#define DUK_ASSERT_HEAPHDR_LINKS(heap,h) do { \
4024 if ((h) != NULL) { \
4025 duk_heaphdr *h__prev, *h__next; \
4026 h__prev = DUK_HEAPHDR_GET_PREV((heap), (h)); \
4027 h__next = DUK_HEAPHDR_GET_NEXT((heap), (h)); \
4028 DUK_ASSERT(h__prev == NULL || (DUK_HEAPHDR_GET_NEXT((heap), h__prev) == (h))); \
4029 DUK_ASSERT(h__next == NULL || (DUK_HEAPHDR_GET_PREV((heap), h__next) == (h))); \
4030 } \
4031 } while (0)
4032#else
4033#define DUK_ASSERT_HEAPHDR_LINKS(heap,h) do {} while (0)
4034#endif
4035
4036/*
4037 * Reference counting helper macros. The macros take a thread argument
4038 * and must thus always be executed in a specific thread context. The
4039 * thread argument is needed for features like finalization. Currently
4040 * it is not required for INCREF, but it is included just in case.
4041 *
4042 * Note that 'raw' macros such as DUK_HEAPHDR_GET_REFCOUNT() are not
4043 * defined without DUK_USE_REFERENCE_COUNTING, so caller must #if defined()
4044 * around them.
4045 */
4046
4047#if defined(DUK_USE_REFERENCE_COUNTING)
4048
4049#if defined(DUK_USE_ROM_OBJECTS)
4050/* With ROM objects "needs refcount update" is true when the value is
4051 * heap allocated and is not a ROM object.
4052 */
4053/* XXX: double evaluation for 'tv' argument. */
4054#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) \
4055 (DUK_TVAL_IS_HEAP_ALLOCATED((tv)) && !DUK_HEAPHDR_HAS_READONLY(DUK_TVAL_GET_HEAPHDR((tv))))
4056#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) (!DUK_HEAPHDR_HAS_READONLY((h)))
4057#else /* DUK_USE_ROM_OBJECTS */
4058/* Without ROM objects "needs refcount update" == is heap allocated. */
4059#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) DUK_TVAL_IS_HEAP_ALLOCATED((tv))
4060#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) 1
4061#endif /* DUK_USE_ROM_OBJECTS */
4062
4063/* Fast variants, inline refcount operations except for refzero handling.
4064 * Can be used explicitly when speed is always more important than size.
4065 * For a good compiler and a single file build, these are basically the
4066 * same as a forced inline.
4067 */
4068#define DUK_TVAL_INCREF_FAST(thr,tv) do { \
4069 duk_tval *duk__tv = (tv); \
4070 DUK_ASSERT(duk__tv != NULL); \
4071 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \
4072 duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \
4073 DUK_ASSERT(duk__h != NULL); \
4074 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
4075 DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \
4076 } \
4077 } while (0)
4078#define DUK_TVAL_DECREF_FAST(thr,tv) do { \
4079 duk_tval *duk__tv = (tv); \
4080 DUK_ASSERT(duk__tv != NULL); \
4081 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \
4082 duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \
4083 DUK_ASSERT(duk__h != NULL); \
4084 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
4085 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \
4086 if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \
4087 duk_heaphdr_refzero((thr), duk__h); \
4088 } \
4089 } \
4090 } while (0)
4091#define DUK_TVAL_DECREF_NORZ_FAST(thr,tv) do { \
4092 duk_tval *duk__tv = (tv); \
4093 DUK_ASSERT(duk__tv != NULL); \
4094 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk__tv)) { \
4095 duk_heaphdr *duk__h = DUK_TVAL_GET_HEAPHDR(duk__tv); \
4096 DUK_ASSERT(duk__h != NULL); \
4097 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
4098 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \
4099 if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \
4100 duk_heaphdr_refzero_norz((thr), duk__h); \
4101 } \
4102 } \
4103 } while (0)
4104#define DUK_HEAPHDR_INCREF_FAST(thr,h) do { \
4105 duk_heaphdr *duk__h = (duk_heaphdr *) (h); \
4106 DUK_ASSERT(duk__h != NULL); \
4107 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
4108 if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \
4109 DUK_HEAPHDR_PREINC_REFCOUNT(duk__h); \
4110 } \
4111 } while (0)
4112#define DUK_HEAPHDR_DECREF_FAST_RAW(thr,h,rzcall,rzcast) do { \
4113 duk_heaphdr *duk__h = (duk_heaphdr *) (h); \
4114 DUK_ASSERT(duk__h != NULL); \
4115 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(duk__h)); \
4116 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(duk__h) > 0); \
4117 if (DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(duk__h)) { \
4118 if (DUK_HEAPHDR_PREDEC_REFCOUNT(duk__h) == 0) { \
4119 (rzcall)((thr), (rzcast) duk__h); \
4120 } \
4121 } \
4122 } while (0)
4123#define DUK_HEAPHDR_DECREF_FAST(thr,h) \
4124 DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero,duk_heaphdr *)
4125#define DUK_HEAPHDR_DECREF_NORZ_FAST(thr,h) \
4126 DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero_norz,duk_heaphdr *)
4127
4128/* Slow variants, call to a helper to reduce code size.
4129 * Can be used explicitly when size is always more important than speed.
4130 */
4131#define DUK_TVAL_INCREF_SLOW(thr,tv) do { duk_tval_incref((tv)); } while (0)
4132#define DUK_TVAL_DECREF_SLOW(thr,tv) do { duk_tval_decref((thr), (tv)); } while (0)
4133#define DUK_TVAL_DECREF_NORZ_SLOW(thr,tv) do { duk_tval_decref_norz((thr), (tv)); } while (0)
4134#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0)
4135#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0)
4136#define DUK_HEAPHDR_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0)
4137#define DUK_HSTRING_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0)
4138#define DUK_HSTRING_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0)
4139#define DUK_HSTRING_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0)
4140#define DUK_HBUFFER_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0)
4141#define DUK_HBUFFER_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0)
4142#define DUK_HBUFFER_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0)
4143#define DUK_HOBJECT_INCREF_SLOW(thr,h) do { duk_heaphdr_incref((duk_heaphdr *) (h)); } while (0)
4144#define DUK_HOBJECT_DECREF_SLOW(thr,h) do { duk_heaphdr_decref((thr), (duk_heaphdr *) (h)); } while (0)
4145#define DUK_HOBJECT_DECREF_NORZ_SLOW(thr,h) do { duk_heaphdr_decref_norz((thr), (duk_heaphdr *) (h)); } while (0)
4146
4147/* Default variants. Selection depends on speed/size preference.
4148 * Concretely: with gcc 4.8.1 -Os x64 the difference in final binary
4149 * is about +1kB for _FAST variants.
4150 */
4151#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
4152/* XXX: It would be nice to specialize for specific duk_hobject subtypes
4153 * but current refzero queue handling prevents that.
4154 */
4155#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_FAST((thr),(tv))
4156#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_FAST((thr),(tv))
4157#define DUK_TVAL_DECREF_NORZ(thr,tv) DUK_TVAL_DECREF_NORZ_FAST((thr),(tv))
4158#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_FAST((thr),(h))
4159#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero,duk_heaphdr *)
4160#define DUK_HEAPHDR_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_heaphdr_refzero_norz,duk_heaphdr *)
4161#define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
4162#define DUK_HSTRING_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hstring_refzero,duk_hstring *)
4163#define DUK_HSTRING_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hstring_refzero,duk_hstring *) /* no 'norz' variant */
4164#define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
4165#define DUK_HOBJECT_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *)
4166#define DUK_HOBJECT_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *)
4167#define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
4168#define DUK_HBUFFER_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hbuffer_refzero,duk_hbuffer *)
4169#define DUK_HBUFFER_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hbuffer_refzero,duk_hbuffer *) /* no 'norz' variant */
4170#define DUK_HCOMPFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
4171#define DUK_HCOMPFUNC_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *)
4172#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *)
4173#define DUK_HNATFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
4174#define DUK_HNATFUNC_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *)
4175#define DUK_HNATFUNC_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *)
4176#define DUK_HBUFOBJ_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
4177#define DUK_HBUFOBJ_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *)
4178#define DUK_HBUFOBJ_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *)
4179#define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
4180#define DUK_HTHREAD_DECREF(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero,duk_hobject *)
4181#define DUK_HTHREAD_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_FAST_RAW((thr),(h),duk_hobject_refzero_norz,duk_hobject *)
4182#else
4183#define DUK_TVAL_INCREF(thr,tv) DUK_TVAL_INCREF_SLOW((thr),(tv))
4184#define DUK_TVAL_DECREF(thr,tv) DUK_TVAL_DECREF_SLOW((thr),(tv))
4185#define DUK_TVAL_DECREF_NORZ(thr,tv) DUK_TVAL_DECREF_NORZ_SLOW((thr),(tv))
4186#define DUK_HEAPHDR_INCREF(thr,h) DUK_HEAPHDR_INCREF_SLOW((thr),(h))
4187#define DUK_HEAPHDR_DECREF(thr,h) DUK_HEAPHDR_DECREF_SLOW((thr),(h))
4188#define DUK_HEAPHDR_DECREF_NORZ(thr,h) DUK_HEAPHDR_DECREF_NORZ_SLOW((thr),(h))
4189#define DUK_HSTRING_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
4190#define DUK_HSTRING_DECREF(thr,h) DUK_HSTRING_DECREF_SLOW((thr),(h))
4191#define DUK_HSTRING_DECREF_NORZ(thr,h) DUK_HSTRING_DECREF_NORZ_SLOW((thr),(h))
4192#define DUK_HOBJECT_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
4193#define DUK_HOBJECT_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(h))
4194#define DUK_HOBJECT_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(h))
4195#define DUK_HBUFFER_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) (h))
4196#define DUK_HBUFFER_DECREF(thr,h) DUK_HBUFFER_DECREF_SLOW((thr),(h))
4197#define DUK_HBUFFER_DECREF_NORZ(thr,h) DUK_HBUFFER_DECREF_NORZ_SLOW((thr),(h))
4198#define DUK_HCOMPFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
4199#define DUK_HCOMPFUNC_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj)
4200#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj)
4201#define DUK_HNATFUNC_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
4202#define DUK_HNATFUNC_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj)
4203#define DUK_HNATFUNC_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj)
4204#define DUK_HBUFOBJ_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
4205#define DUK_HBUFOBJ_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj)
4206#define DUK_HBUFOB_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj)
4207#define DUK_HTHREAD_INCREF(thr,h) DUK_HEAPHDR_INCREF((thr),(duk_heaphdr *) &(h)->obj)
4208#define DUK_HTHREAD_DECREF(thr,h) DUK_HOBJECT_DECREF_SLOW((thr),(duk_hobject *) &(h)->obj)
4209#define DUK_HTHREAD_DECREF_NORZ(thr,h) DUK_HOBJECT_DECREF_NORZ_SLOW((thr),(duk_hobject *) &(h)->obj)
4210#endif
4211
4212/* Convenience for some situations; the above macros don't allow NULLs
4213 * for performance reasons. Macros cover only actually needed cases.
4214 */
4215#define DUK_HEAPHDR_INCREF_ALLOWNULL(thr,h) do { \
4216 if ((h) != NULL) { \
4217 DUK_HEAPHDR_INCREF((thr), (duk_heaphdr *) (h)); \
4218 } \
4219 } while (0)
4220#define DUK_HEAPHDR_DECREF_ALLOWNULL(thr,h) do { \
4221 if ((h) != NULL) { \
4222 DUK_HEAPHDR_DECREF((thr), (duk_heaphdr *) (h)); \
4223 } \
4224 } while (0)
4225#define DUK_HEAPHDR_DECREF_NORZ_ALLOWNULL(thr,h) do { \
4226 if ((h) != NULL) { \
4227 DUK_HEAPHDR_DECREF_NORZ((thr), (duk_heaphdr *) (h)); \
4228 } \
4229 } while (0)
4230#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do { \
4231 if ((h) != NULL) { \
4232 DUK_HOBJECT_INCREF((thr), (h)); \
4233 } \
4234 } while (0)
4235#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do { \
4236 if ((h) != NULL) { \
4237 DUK_HOBJECT_DECREF((thr), (h)); \
4238 } \
4239 } while (0)
4240#define DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr,h) do { \
4241 if ((h) != NULL) { \
4242 DUK_HOBJECT_DECREF_NORZ((thr), (h)); \
4243 } \
4244 } while (0)
4245#define DUK_HBUFFER_INCREF_ALLOWNULL(thr,h) do { \
4246 if ((h) != NULL) { \
4247 DUK_HBUFFER_INCREF((thr), (h)); \
4248 } \
4249 } while (0)
4250#define DUK_HBUFFER_DECREF_ALLOWNULL(thr,h) do { \
4251 if ((h) != NULL) { \
4252 DUK_HBUFFER_DECREF((thr), (h)); \
4253 } \
4254 } while (0)
4255#define DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr,h) do { \
4256 if ((h) != NULL) { \
4257 DUK_HBUFFER_DECREF_NORZ((thr), (h)); \
4258 } \
4259 } while (0)
4260#define DUK_HTHREAD_INCREF_ALLOWNULL(thr,h) do { \
4261 if ((h) != NULL) { \
4262 DUK_HTHREAD_INCREF((thr), (h)); \
4263 } \
4264 } while (0)
4265#define DUK_HTHREAD_DECREF_ALLOWNULL(thr,h) do { \
4266 if ((h) != NULL) { \
4267 DUK_HTHREAD_DECREF((thr), (h)); \
4268 } \
4269 } while (0)
4270#define DUK_HTHREAD_DECREF_NORZ_ALLOWNULL(thr,h) do { \
4271 if ((h) != NULL) { \
4272 DUK_HTHREAD_DECREF_NORZ((thr), (h)); \
4273 } \
4274 } while (0)
4275
4276/* Free pending refzero entries; quick check to avoid call because often
4277 * the queue is empty.
4278 */
4279#define DUK_REFZERO_CHECK_FAST(thr) do { \
4280 if ((thr)->heap->refzero_list != NULL) { \
4281 duk_refzero_free_pending((thr)); \
4282 } \
4283 } while (0)
4284#define DUK_REFZERO_CHECK_SLOW(thr) do { \
4285 duk_refzero_free_pending((thr)); \
4286 } while (0)
4287
4288/*
4289 * Macros to set a duk_tval and update refcount of the target (decref the
4290 * old value and incref the new value if necessary). This is both performance
4291 * and footprint critical; any changes made should be measured for size/speed.
4292 */
4293
4294#define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \
4295 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
4296 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
4297 DUK_TVAL_SET_UNDEFINED(tv__dst); \
4298 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
4299 } while (0)
4300
4301#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ_ALT0(thr,tvptr_dst) do { \
4302 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
4303 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
4304 DUK_TVAL_SET_UNDEFINED(tv__dst); \
4305 DUK_TVAL_DECREF_NORZ((thr), &tv__tmp); \
4306 } while (0)
4307
4308#define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \
4309 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
4310 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
4311 DUK_TVAL_SET_UNUSED(tv__dst); \
4312 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
4313 } while (0)
4314
4315#define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \
4316 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
4317 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
4318 DUK_TVAL_SET_NULL(tv__dst); \
4319 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
4320 } while (0)
4321
4322#define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4323 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
4324 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
4325 DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \
4326 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
4327 } while (0)
4328
4329#define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4330 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
4331 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
4332 DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \
4333 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
4334 } while (0)
4335#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4336 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
4337 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
4338 DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv__dst, (newval)); \
4339 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
4340 } while (0)
4341#define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4342 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
4343 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
4344 DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \
4345 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
4346 } while (0)
4347#define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \
4348 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
4349 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
4350 DUK_TVAL_SET_NAN(tv__dst); \
4351 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
4352 } while (0)
4353#if defined(DUK_USE_FASTINT)
4354#define DUK_TVAL_SET_I48_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4355 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
4356 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
4357 DUK_TVAL_SET_I48(tv__dst, (newval)); \
4358 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
4359 } while (0)
4360#define DUK_TVAL_SET_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4361 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
4362 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
4363 DUK_TVAL_SET_I32(tv__dst, (newval)); \
4364 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
4365 } while (0)
4366#define DUK_TVAL_SET_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4367 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
4368 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
4369 DUK_TVAL_SET_U32(tv__dst, (newval)); \
4370 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
4371 } while (0)
4372#else
4373#define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \
4374 DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval))
4375#endif /* DUK_USE_FASTINT */
4376
4377#define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) do { \
4378 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
4379 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
4380 DUK_TVAL_SET_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \
4381 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
4382 } while (0)
4383
4384#define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4385 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
4386 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
4387 DUK_TVAL_SET_STRING(tv__dst, (newval)); \
4388 DUK_HSTRING_INCREF((thr), (newval)); \
4389 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
4390 } while (0)
4391
4392#define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4393 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
4394 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
4395 DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \
4396 DUK_HOBJECT_INCREF((thr), (newval)); \
4397 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
4398 } while (0)
4399
4400#define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4401 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
4402 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
4403 DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \
4404 DUK_HBUFFER_INCREF((thr), (newval)); \
4405 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
4406 } while (0)
4407
4408#define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4409 duk_tval *tv__dst; duk_tval tv__tmp; tv__dst = (tvptr_dst); \
4410 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
4411 DUK_TVAL_SET_POINTER(tv__dst, (newval)); \
4412 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
4413 } while (0)
4414
4415/* DUK_TVAL_SET_TVAL_UPDREF() is used a lot in executor, property lookups,
4416 * etc, so it's very important for performance. Measure when changing.
4417 *
4418 * NOTE: the source and destination duk_tval pointers may be the same, and
4419 * the macros MUST deal with that correctly.
4420 */
4421
4422/* Original idiom used, minimal code size. */
4423#define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \
4424 duk_tval *tv__dst, *tv__src; duk_tval tv__tmp; \
4425 tv__dst = (tvptr_dst); tv__src = (tvptr_src); \
4426 DUK_TVAL_SET_TVAL(&tv__tmp, tv__dst); \
4427 DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
4428 DUK_TVAL_INCREF((thr), tv__src); \
4429 DUK_TVAL_DECREF((thr), &tv__tmp); /* side effects */ \
4430 } while (0)
4431
4432/* Faster alternative: avoid making a temporary copy of tvptr_dst and use
4433 * fast incref/decref macros.
4434 */
4435#define DUK_TVAL_SET_TVAL_UPDREF_ALT1(thr,tvptr_dst,tvptr_src) do { \
4436 duk_tval *tv__dst, *tv__src; duk_heaphdr *h__obj; \
4437 tv__dst = (tvptr_dst); tv__src = (tvptr_src); \
4438 DUK_TVAL_INCREF_FAST((thr), tv__src); \
4439 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv__dst)) { \
4440 h__obj = DUK_TVAL_GET_HEAPHDR(tv__dst); \
4441 DUK_ASSERT(h__obj != NULL); \
4442 DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
4443 DUK_HEAPHDR_DECREF_FAST((thr), h__obj); /* side effects */ \
4444 } else { \
4445 DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
4446 } \
4447 } while (0)
4448
4449/* XXX: no optimized variants yet */
4450#define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0
4451#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ_ALT0
4452#define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0
4453#define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0
4454#define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0
4455#define DUK_TVAL_SET_NUMBER_UPDREF DUK_TVAL_SET_NUMBER_UPDREF_ALT0
4456#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0
4457#define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0
4458#define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0
4459#if defined(DUK_USE_FASTINT)
4460#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_I48_UPDREF_ALT0
4461#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_I32_UPDREF_ALT0
4462#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_U32_UPDREF_ALT0
4463#else
4464#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast int-to-double */
4465#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
4466#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
4467#endif /* DUK_USE_FASTINT */
4468#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_I48_UPDREF /* convenience */
4469#define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0
4470#define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0
4471#define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0
4472#define DUK_TVAL_SET_BUFFER_UPDREF DUK_TVAL_SET_BUFFER_UPDREF_ALT0
4473#define DUK_TVAL_SET_POINTER_UPDREF DUK_TVAL_SET_POINTER_UPDREF_ALT0
4474
4475#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
4476/* Optimized for speed. */
4477#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT1
4478#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT1
4479#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0
4480#else
4481/* Optimized for size. */
4482#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT0
4483#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT0
4484#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0
4485#endif
4486
4487#else /* DUK_USE_REFERENCE_COUNTING */
4488
4489#define DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv) 0
4490#define DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE(h) 0
4491
4492#define DUK_TVAL_INCREF_FAST(thr,v) do {} while (0) /* nop */
4493#define DUK_TVAL_DECREF_FAST(thr,v) do {} while (0) /* nop */
4494#define DUK_TVAL_DECREF_NORZ_FAST(thr,v) do {} while (0) /* nop */
4495#define DUK_TVAL_INCREF_SLOW(thr,v) do {} while (0) /* nop */
4496#define DUK_TVAL_DECREF_SLOW(thr,v) do {} while (0) /* nop */
4497#define DUK_TVAL_DECREF_NORZ_SLOW(thr,v) do {} while (0) /* nop */
4498#define DUK_TVAL_INCREF(thr,v) do {} while (0) /* nop */
4499#define DUK_TVAL_DECREF(thr,v) do {} while (0) /* nop */
4500#define DUK_TVAL_DECREF_NORZ(thr,v) do {} while (0) /* nop */
4501#define DUK_HEAPHDR_INCREF_FAST(thr,h) do {} while (0) /* nop */
4502#define DUK_HEAPHDR_DECREF_FAST(thr,h) do {} while (0) /* nop */
4503#define DUK_HEAPHDR_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */
4504#define DUK_HEAPHDR_INCREF_SLOW(thr,h) do {} while (0) /* nop */
4505#define DUK_HEAPHDR_DECREF_SLOW(thr,h) do {} while (0) /* nop */
4506#define DUK_HEAPHDR_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */
4507#define DUK_HEAPHDR_INCREF(thr,h) do {} while (0) /* nop */
4508#define DUK_HEAPHDR_DECREF(thr,h) do {} while (0) /* nop */
4509#define DUK_HEAPHDR_DECREF_NORZ(thr,h) do {} while (0) /* nop */
4510#define DUK_HSTRING_INCREF_FAST(thr,h) do {} while (0) /* nop */
4511#define DUK_HSTRING_DECREF_FAST(thr,h) do {} while (0) /* nop */
4512#define DUK_HSTRING_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */
4513#define DUK_HSTRING_INCREF_SLOW(thr,h) do {} while (0) /* nop */
4514#define DUK_HSTRING_DECREF_SLOW(thr,h) do {} while (0) /* nop */
4515#define DUK_HSTRING_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */
4516#define DUK_HSTRING_INCREF(thr,h) do {} while (0) /* nop */
4517#define DUK_HSTRING_DECREF(thr,h) do {} while (0) /* nop */
4518#define DUK_HSTRING_DECREF_NORZ(thr,h) do {} while (0) /* nop */
4519#define DUK_HOBJECT_INCREF_FAST(thr,h) do {} while (0) /* nop */
4520#define DUK_HOBJECT_DECREF_FAST(thr,h) do {} while (0) /* nop */
4521#define DUK_HOBJECT_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */
4522#define DUK_HOBJECT_INCREF_SLOW(thr,h) do {} while (0) /* nop */
4523#define DUK_HOBJECT_DECREF_SLOW(thr,h) do {} while (0) /* nop */
4524#define DUK_HOBJECT_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */
4525#define DUK_HOBJECT_INCREF(thr,h) do {} while (0) /* nop */
4526#define DUK_HOBJECT_DECREF(thr,h) do {} while (0) /* nop */
4527#define DUK_HOBJECT_DECREF_NORZ(thr,h) do {} while (0) /* nop */
4528#define DUK_HBUFFER_INCREF_FAST(thr,h) do {} while (0) /* nop */
4529#define DUK_HBUFFER_DECREF_FAST(thr,h) do {} while (0) /* nop */
4530#define DUK_HBUFFER_DECREF_NORZ_FAST(thr,h) do {} while (0) /* nop */
4531#define DUK_HBUFFER_INCREF_SLOW(thr,h) do {} while (0) /* nop */
4532#define DUK_HBUFFER_DECREF_SLOW(thr,h) do {} while (0) /* nop */
4533#define DUK_HBUFFER_DECREF_NORZ_SLOW(thr,h) do {} while (0) /* nop */
4534#define DUK_HBUFFER_INCREF(thr,h) do {} while (0) /* nop */
4535#define DUK_HBUFFER_DECREF(thr,h) do {} while (0) /* nop */
4536#define DUK_HBUFFER_DECREF_NORZ(thr,h) do {} while (0) /* nop */
4537
4538#define DUK_HCOMPFUNC_INCREF(thr,h) do {} while (0) /* nop */
4539#define DUK_HCOMPFUNC_DECREF(thr,h) do {} while (0) /* nop */
4540#define DUK_HCOMPFUNC_DECREF_NORZ(thr,h) do {} while (0) /* nop */
4541#define DUK_HNATFUNC_INCREF(thr,h) do {} while (0) /* nop */
4542#define DUK_HNATFUNC_DECREF(thr,h) do {} while (0) /* nop */
4543#define DUK_HNATFUNC_DECREF_NORZ(thr,h) do {} while (0) /* nop */
4544#define DUK_HBUFOBJ_INCREF(thr,h) do {} while (0) /* nop */
4545#define DUK_HBUFOBJ_DECREF(thr,h) do {} while (0) /* nop */
4546#define DUK_HBUFOBJ_DECREF_NORZ(thr,h) do {} while (0) /* nop */
4547#define DUK_HTHREAD_INCREF(thr,h) do {} while (0) /* nop */
4548#define DUK_HTHREAD_DECREF(thr,h) do {} while (0) /* nop */
4549#define DUK_HTHREAD_DECREF_NORZ(thr,h) do {} while (0) /* nop */
4550#define DUK_HOBJECT_INCREF_ALLOWNULL(thr,h) do {} while (0) /* nop */
4551#define DUK_HOBJECT_DECREF_ALLOWNULL(thr,h) do {} while (0) /* nop */
4552#define DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr,h) do {} while (0) /* nop */
4553#define DUK_HBUFFER_INCREF_ALLOWNULL(thr,h) do {} while (0) /* nop */
4554#define DUK_HBUFFER_DECREF_ALLOWNULL(thr,h) do {} while (0) /* nop */
4555#define DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr,h) do {} while (0) /* nop */
4556
4557#define DUK_REFZERO_CHECK_FAST(thr) do {} while (0) /* nop */
4558#define DUK_REFZERO_CHECK_SLOW(thr) do {} while (0) /* nop */
4559
4560#define DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0(thr,tvptr_dst) do { \
4561 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4562 DUK_TVAL_SET_UNDEFINED(tv__dst); \
4563 DUK_UNREF((thr)); \
4564 } while (0)
4565
4566#define DUK_TVAL_SET_UNUSED_UPDREF_ALT0(thr,tvptr_dst) do { \
4567 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4568 DUK_TVAL_SET_UNUSED(tv__dst); \
4569 DUK_UNREF((thr)); \
4570 } while (0)
4571
4572#define DUK_TVAL_SET_NULL_UPDREF_ALT0(thr,tvptr_dst) do { \
4573 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4574 DUK_TVAL_SET_NULL(tv__dst); \
4575 DUK_UNREF((thr)); \
4576 } while (0)
4577
4578#define DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4579 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4580 DUK_TVAL_SET_BOOLEAN(tv__dst, (newval)); \
4581 DUK_UNREF((thr)); \
4582 } while (0)
4583
4584#define DUK_TVAL_SET_NUMBER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4585 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4586 DUK_TVAL_SET_NUMBER(tv__dst, (newval)); \
4587 DUK_UNREF((thr)); \
4588 } while (0)
4589#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4590 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4591 DUK_TVAL_SET_NUMBER_CHKFAST_FAST(tv__dst, (newval)); \
4592 DUK_UNREF((thr)); \
4593 } while (0)
4594#define DUK_TVAL_SET_DOUBLE_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4595 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4596 DUK_TVAL_SET_DOUBLE(tv__dst, (newval)); \
4597 DUK_UNREF((thr)); \
4598 } while (0)
4599#define DUK_TVAL_SET_NAN_UPDREF_ALT0(thr,tvptr_dst) do { \
4600 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4601 DUK_TVAL_SET_NAN(tv__dst); \
4602 DUK_UNREF((thr)); \
4603 } while (0)
4604#if defined(DUK_USE_FASTINT)
4605#define DUK_TVAL_SET_I48_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4606 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4607 DUK_TVAL_SET_I48(tv__dst, (newval)); \
4608 DUK_UNREF((thr)); \
4609 } while (0)
4610#define DUK_TVAL_SET_I32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4611 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4612 DUK_TVAL_SET_I32(tv__dst, (newval)); \
4613 DUK_UNREF((thr)); \
4614 } while (0)
4615#define DUK_TVAL_SET_U32_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4616 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4617 DUK_TVAL_SET_U32(tv__dst, (newval)); \
4618 DUK_UNREF((thr)); \
4619 } while (0)
4620#else
4621#define DUK_TVAL_SET_DOUBLE_CAST_UPDREF(thr,tvptr_dst,newval) \
4622 DUK_TVAL_SET_DOUBLE_UPDREF((thr), (tvptr_dst), (duk_double_t) (newval))
4623#endif /* DUK_USE_FASTINT */
4624
4625#define DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0(thr,tvptr_dst,lf_v,lf_fp,lf_flags) do { \
4626 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4627 DUK_TVAL_SET_LIGHTFUNC(tv__dst, (lf_v), (lf_fp), (lf_flags)); \
4628 DUK_UNREF((thr)); \
4629 } while (0)
4630
4631#define DUK_TVAL_SET_STRING_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4632 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4633 DUK_TVAL_SET_STRING(tv__dst, (newval)); \
4634 DUK_UNREF((thr)); \
4635 } while (0)
4636
4637#define DUK_TVAL_SET_OBJECT_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4638 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4639 DUK_TVAL_SET_OBJECT(tv__dst, (newval)); \
4640 DUK_UNREF((thr)); \
4641 } while (0)
4642
4643#define DUK_TVAL_SET_BUFFER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4644 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4645 DUK_TVAL_SET_BUFFER(tv__dst, (newval)); \
4646 DUK_UNREF((thr)); \
4647 } while (0)
4648
4649#define DUK_TVAL_SET_POINTER_UPDREF_ALT0(thr,tvptr_dst,newval) do { \
4650 duk_tval *tv__dst; tv__dst = (tvptr_dst); \
4651 DUK_TVAL_SET_POINTER(tv__dst, (newval)); \
4652 DUK_UNREF((thr)); \
4653 } while (0)
4654
4655#define DUK_TVAL_SET_TVAL_UPDREF_ALT0(thr,tvptr_dst,tvptr_src) do { \
4656 duk_tval *tv__dst, *tv__src; \
4657 tv__dst = (tvptr_dst); tv__src = (tvptr_src); \
4658 DUK_TVAL_SET_TVAL(tv__dst, tv__src); \
4659 DUK_UNREF((thr)); \
4660 } while (0)
4661
4662#define DUK_TVAL_SET_UNDEFINED_UPDREF DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0
4663#define DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ DUK_TVAL_SET_UNDEFINED_UPDREF_ALT0
4664#define DUK_TVAL_SET_UNUSED_UPDREF DUK_TVAL_SET_UNUSED_UPDREF_ALT0
4665#define DUK_TVAL_SET_NULL_UPDREF DUK_TVAL_SET_NULL_UPDREF_ALT0
4666#define DUK_TVAL_SET_BOOLEAN_UPDREF DUK_TVAL_SET_BOOLEAN_UPDREF_ALT0
4667#define DUK_TVAL_SET_NUMBER_UPDREF DUK_TVAL_SET_NUMBER_UPDREF_ALT0
4668#define DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF_ALT0
4669#define DUK_TVAL_SET_DOUBLE_UPDREF DUK_TVAL_SET_DOUBLE_UPDREF_ALT0
4670#define DUK_TVAL_SET_NAN_UPDREF DUK_TVAL_SET_NAN_UPDREF_ALT0
4671#if defined(DUK_USE_FASTINT)
4672#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_I48_UPDREF_ALT0
4673#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_I32_UPDREF_ALT0
4674#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_U32_UPDREF_ALT0
4675#else
4676#define DUK_TVAL_SET_I48_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF /* XXX: fast-int-to-double */
4677#define DUK_TVAL_SET_I32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
4678#define DUK_TVAL_SET_U32_UPDREF DUK_TVAL_SET_DOUBLE_CAST_UPDREF
4679#endif /* DUK_USE_FASTINT */
4680#define DUK_TVAL_SET_FASTINT_UPDREF DUK_TVAL_SET_I48_UPDREF /* convenience */
4681#define DUK_TVAL_SET_LIGHTFUNC_UPDREF DUK_TVAL_SET_LIGHTFUNC_UPDREF_ALT0
4682#define DUK_TVAL_SET_STRING_UPDREF DUK_TVAL_SET_STRING_UPDREF_ALT0
4683#define DUK_TVAL_SET_OBJECT_UPDREF DUK_TVAL_SET_OBJECT_UPDREF_ALT0
4684#define DUK_TVAL_SET_BUFFER_UPDREF DUK_TVAL_SET_BUFFER_UPDREF_ALT0
4685#define DUK_TVAL_SET_POINTER_UPDREF DUK_TVAL_SET_POINTER_UPDREF_ALT0
4686
4687#define DUK_TVAL_SET_TVAL_UPDREF DUK_TVAL_SET_TVAL_UPDREF_ALT0
4688#define DUK_TVAL_SET_TVAL_UPDREF_FAST DUK_TVAL_SET_TVAL_UPDREF_ALT0
4689#define DUK_TVAL_SET_TVAL_UPDREF_SLOW DUK_TVAL_SET_TVAL_UPDREF_ALT0
4690
4691#endif /* DUK_USE_REFERENCE_COUNTING */
4692
4693#endif /* DUK_HEAPHDR_H_INCLUDED */
4694/* #include duk_api_internal.h */
4695/*
4696 * Internal API calls which have (stack and other) semantics similar
4697 * to the public API.
4698 */
4699
4700#if !defined(DUK_API_INTERNAL_H_INCLUDED)
4701#define DUK_API_INTERNAL_H_INCLUDED
4702
4703/* duk_push_sprintf constants */
4704#define DUK_PUSH_SPRINTF_INITIAL_SIZE 256L
4705#define DUK_PUSH_SPRINTF_SANITY_LIMIT (1L * 1024L * 1024L * 1024L)
4706
4707/* Flag ORed to err_code to indicate __FILE__ / __LINE__ is not
4708 * blamed as source of error for error fileName / lineNumber.
4709 */
4710#define DUK_ERRCODE_FLAG_NOBLAME_FILELINE (1L << 24)
4711
4712/* Valstack resize flags */
4713#define DUK_VSRESIZE_FLAG_SHRINK (1 << 0)
4714#define DUK_VSRESIZE_FLAG_COMPACT (1 << 1)
4715#define DUK_VSRESIZE_FLAG_THROW (1 << 2)
4716
4717/* Current convention is to use duk_size_t for value stack sizes and global indices,
4718 * and duk_idx_t for local frame indices.
4719 */
4720DUK_INTERNAL_DECL
4721duk_bool_t duk_valstack_resize_raw(duk_context *ctx,
4722 duk_size_t min_new_size,
4723 duk_small_uint_t flags);
4724
4725DUK_INTERNAL_DECL void duk_dup_0(duk_context *ctx);
4726DUK_INTERNAL_DECL void duk_dup_1(duk_context *ctx);
4727DUK_INTERNAL_DECL void duk_dup_2(duk_context *ctx);
4728/* duk_dup_m1() would be same as duk_dup_top() */
4729DUK_INTERNAL_DECL void duk_dup_m2(duk_context *ctx);
4730DUK_INTERNAL_DECL void duk_dup_m3(duk_context *ctx);
4731DUK_INTERNAL_DECL void duk_dup_m4(duk_context *ctx);
4732
4733DUK_INTERNAL_DECL void duk_remove_m2(duk_context *ctx);
4734
4735DUK_INTERNAL_DECL duk_int_t duk_get_type_tval(duk_tval *tv);
4736DUK_INTERNAL_DECL duk_uint_t duk_get_type_mask_tval(duk_tval *tv);
4737
4738#if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS)
4739DUK_INTERNAL_DECL const char *duk_get_type_name(duk_context *ctx, duk_idx_t idx);
4740#endif
4741DUK_INTERNAL_DECL duk_small_uint_t duk_get_class_number(duk_context *ctx, duk_idx_t idx);
4742
4743DUK_INTERNAL_DECL duk_tval *duk_get_tval(duk_context *ctx, duk_idx_t idx);
4744DUK_INTERNAL_DECL duk_tval *duk_get_tval_or_unused(duk_context *ctx, duk_idx_t idx);
4745DUK_INTERNAL_DECL duk_tval *duk_require_tval(duk_context *ctx, duk_idx_t idx);
4746DUK_INTERNAL_DECL void duk_push_tval(duk_context *ctx, duk_tval *tv);
4747
4748/* Push the current 'this' binding; throw TypeError if binding is not object
4749 * coercible (CheckObjectCoercible).
4750 */
4751DUK_INTERNAL_DECL void duk_push_this_check_object_coercible(duk_context *ctx);
4752
4753/* duk_push_this() + CheckObjectCoercible() + duk_to_object() */
4754DUK_INTERNAL_DECL duk_hobject *duk_push_this_coercible_to_object(duk_context *ctx);
4755
4756/* duk_push_this() + CheckObjectCoercible() + duk_to_string() */
4757DUK_INTERNAL_DECL duk_hstring *duk_push_this_coercible_to_string(duk_context *ctx);
4758
4759DUK_INTERNAL_DECL duk_hstring *duk_push_uint_to_hstring(duk_context *ctx, duk_uint_t i);
4760
4761/* Get a borrowed duk_tval pointer to the current 'this' binding. Caller must
4762 * make sure there's an active callstack entry. Note that the returned pointer
4763 * is unstable with regards to side effects.
4764 */
4765DUK_INTERNAL_DECL duk_tval *duk_get_borrowed_this_tval(duk_context *ctx);
4766
4767/* XXX: add fastint support? */
4768#define duk_push_u64(ctx,val) \
4769 duk_push_number((ctx), (duk_double_t) (val))
4770#define duk_push_i64(ctx,val) \
4771 duk_push_number((ctx), (duk_double_t) (val))
4772
4773/* duk_push_(u)int() is guaranteed to support at least (un)signed 32-bit range */
4774#define duk_push_u32(ctx,val) \
4775 duk_push_uint((ctx), (duk_uint_t) (val))
4776#define duk_push_i32(ctx,val) \
4777 duk_push_int((ctx), (duk_int_t) (val))
4778
4779/* sometimes stack and array indices need to go on the stack */
4780#define duk_push_idx(ctx,val) \
4781 duk_push_int((ctx), (duk_int_t) (val))
4782#define duk_push_uarridx(ctx,val) \
4783 duk_push_uint((ctx), (duk_uint_t) (val))
4784#define duk_push_size_t(ctx,val) \
4785 duk_push_uint((ctx), (duk_uint_t) (val)) /* XXX: assumed to fit for now */
4786
4787DUK_INTERNAL_DECL duk_bool_t duk_is_string_notsymbol(duk_context *ctx, duk_idx_t idx);
4788
4789DUK_INTERNAL_DECL duk_hstring *duk_get_hstring(duk_context *ctx, duk_idx_t idx);
4790DUK_INTERNAL_DECL duk_hstring *duk_get_hstring_notsymbol(duk_context *ctx, duk_idx_t idx);
4791DUK_INTERNAL_DECL const char *duk_get_string_notsymbol(duk_context *ctx, duk_idx_t idx);
4792DUK_INTERNAL_DECL duk_hobject *duk_get_hobject(duk_context *ctx, duk_idx_t idx);
4793DUK_INTERNAL_DECL duk_hbuffer *duk_get_hbuffer(duk_context *ctx, duk_idx_t idx);
4794DUK_INTERNAL_DECL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t idx);
4795DUK_INTERNAL_DECL duk_hcompfunc *duk_get_hcompfunc(duk_context *ctx, duk_idx_t idx);
4796DUK_INTERNAL_DECL duk_hnatfunc *duk_get_hnatfunc(duk_context *ctx, duk_idx_t idx);
4797
4798DUK_INTERNAL_DECL void *duk_get_buffer_data_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_bool_t throw_flag, duk_bool_t *out_found);
4799
4800DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_with_class(duk_context *ctx, duk_idx_t idx, duk_small_uint_t classnum);
4801
4802DUK_INTERNAL_DECL duk_hobject *duk_get_hobject_promote_mask(duk_context *ctx, duk_idx_t idx, duk_uint_t type_mask);
4803DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_promote_mask(duk_context *ctx, duk_idx_t idx, duk_uint_t type_mask);
4804DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_accept_mask(duk_context *ctx, duk_idx_t idx, duk_uint_t type_mask);
4805#define duk_require_hobject_promote_lfunc(ctx,idx) \
4806 duk_require_hobject_promote_mask((ctx), (idx), DUK_TYPE_MASK_LIGHTFUNC)
4807#define duk_get_hobject_promote_lfunc(ctx,idx) \
4808 duk_get_hobject_promote_mask((ctx), (idx), DUK_TYPE_MASK_LIGHTFUNC)
4809
4810#if 0 /*unused*/
4811DUK_INTERNAL_DECL void *duk_get_voidptr(duk_context *ctx, duk_idx_t idx);
4812#endif
4813
4814DUK_INTERNAL_DECL duk_hstring *duk_known_hstring(duk_context *ctx, duk_idx_t idx);
4815DUK_INTERNAL_DECL duk_hobject *duk_known_hobject(duk_context *ctx, duk_idx_t idx);
4816DUK_INTERNAL_DECL duk_hbuffer *duk_known_hbuffer(duk_context *ctx, duk_idx_t idx);
4817DUK_INTERNAL_DECL duk_hcompfunc *duk_known_hcompfunc(duk_context *ctx, duk_idx_t idx);
4818DUK_INTERNAL_DECL duk_hnatfunc *duk_known_hnatfunc(duk_context *ctx, duk_idx_t idx);
4819
4820DUK_INTERNAL_DECL duk_double_t duk_to_number_tval(duk_context *ctx, duk_tval *tv);
4821
4822DUK_INTERNAL_DECL duk_hstring *duk_to_hstring(duk_context *ctx, duk_idx_t idx);
4823DUK_INTERNAL_DECL duk_hstring *duk_to_hstring_m1(duk_context *ctx);
4824DUK_INTERNAL_DECL duk_hstring *duk_to_hstring_acceptsymbol(duk_context *ctx, duk_idx_t idx);
4825
4826DUK_INTERNAL_DECL duk_hobject *duk_to_hobject(duk_context *ctx, duk_idx_t idx);
4827
4828DUK_INTERNAL_DECL duk_double_t duk_to_number_m1(duk_context *ctx);
4829DUK_INTERNAL_DECL duk_double_t duk_to_number_m2(duk_context *ctx);
4830
4831#if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */
4832DUK_INTERNAL_DECL duk_hstring *duk_safe_to_hstring(duk_context *ctx, duk_idx_t idx);
4833#endif
4834DUK_INTERNAL_DECL void duk_push_class_string_tval(duk_context *ctx, duk_tval *tv);
4835
4836DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t idx, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped); /* out_clamped=NULL, RangeError if outside range */
4837DUK_INTERNAL_DECL duk_int_t duk_to_int_clamped(duk_context *ctx, duk_idx_t idx, duk_int_t minval, duk_int_t maxval);
4838DUK_INTERNAL_DECL duk_int_t duk_to_int_check_range(duk_context *ctx, duk_idx_t idx, duk_int_t minval, duk_int_t maxval);
4839#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
4840DUK_INTERNAL_DECL duk_uint8_t duk_to_uint8clamped(duk_context *ctx, duk_idx_t idx);
4841#endif
4842DUK_INTERNAL_DECL duk_hstring *duk_to_property_key_hstring(duk_context *ctx, duk_idx_t idx);
4843
4844DUK_INTERNAL_DECL duk_hstring *duk_require_hstring(duk_context *ctx, duk_idx_t idx);
4845DUK_INTERNAL_DECL duk_hstring *duk_require_hstring_notsymbol(duk_context *ctx, duk_idx_t idx);
4846DUK_INTERNAL_DECL const char *duk_require_lstring_notsymbol(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len);
4847DUK_INTERNAL_DECL const char *duk_require_string_notsymbol(duk_context *ctx, duk_idx_t idx);
4848DUK_INTERNAL_DECL duk_hobject *duk_require_hobject(duk_context *ctx, duk_idx_t idx);
4849DUK_INTERNAL_DECL duk_hbuffer *duk_require_hbuffer(duk_context *ctx, duk_idx_t idx);
4850DUK_INTERNAL_DECL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t idx);
4851DUK_INTERNAL_DECL duk_hcompfunc *duk_require_hcompfunc(duk_context *ctx, duk_idx_t idx);
4852DUK_INTERNAL_DECL duk_hnatfunc *duk_require_hnatfunc(duk_context *ctx, duk_idx_t idx);
4853
4854DUK_INTERNAL_DECL duk_hobject *duk_require_hobject_with_class(duk_context *ctx, duk_idx_t idx, duk_small_uint_t classnum);
4855
4856DUK_INTERNAL_DECL void duk_push_hstring(duk_context *ctx, duk_hstring *h);
4857DUK_INTERNAL_DECL void duk_push_hstring_stridx(duk_context *ctx, duk_small_uint_t stridx);
4858DUK_INTERNAL_DECL void duk_push_hstring_empty(duk_context *ctx);
4859DUK_INTERNAL_DECL void duk_push_hobject(duk_context *ctx, duk_hobject *h);
4860DUK_INTERNAL_DECL void duk_push_hbuffer(duk_context *ctx, duk_hbuffer *h);
4861#define duk_push_hthread(ctx,h) \
4862 duk_push_hobject((ctx), (duk_hobject *) (h))
4863#define duk_push_hnatfunc(ctx,h) \
4864 duk_push_hobject((ctx), (duk_hobject *) (h))
4865DUK_INTERNAL_DECL void duk_push_hobject_bidx(duk_context *ctx, duk_small_int_t builtin_idx);
4866DUK_INTERNAL_DECL duk_hobject *duk_push_object_helper(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx);
4867DUK_INTERNAL_DECL duk_hobject *duk_push_object_helper_proto(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_hobject *proto);
4868DUK_INTERNAL_DECL duk_hcompfunc *duk_push_hcompfunc(duk_context *ctx);
4869DUK_INTERNAL_DECL void duk_push_c_function_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs);
4870DUK_INTERNAL_DECL void duk_push_c_function_noconstruct_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs);
4871
4872/* XXX: duk_push_harray() and duk_push_hcompfunc() are inconsistent with
4873 * duk_push_hobject() etc which don't create a new value.
4874 */
4875DUK_INTERNAL_DECL duk_harray *duk_push_harray(duk_context *ctx);
4876DUK_INTERNAL_DECL duk_harray *duk_push_harray_with_size(duk_context *ctx, duk_uint32_t size);
4877
4878DUK_INTERNAL_DECL void duk_push_string_funcptr(duk_context *ctx, duk_uint8_t *ptr, duk_size_t sz);
4879DUK_INTERNAL_DECL void duk_push_lightfunc_name_raw(duk_context *ctx, duk_c_function func, duk_small_uint_t lf_flags);
4880DUK_INTERNAL_DECL void duk_push_lightfunc_name(duk_context *ctx, duk_tval *tv);
4881DUK_INTERNAL_DECL void duk_push_lightfunc_tostring(duk_context *ctx, duk_tval *tv);
4882#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
4883DUK_INTERNAL_DECL duk_hbufobj *duk_push_bufobj_raw(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx);
4884#endif
4885
4886DUK_INTERNAL_DECL void *duk_push_fixed_buffer_nozero(duk_context *ctx, duk_size_t len);
4887DUK_INTERNAL_DECL void *duk_push_fixed_buffer_zero(duk_context *ctx, duk_size_t len);
4888
4889DUK_INTERNAL_DECL const char *duk_push_string_readable(duk_context *ctx, duk_idx_t idx);
4890DUK_INTERNAL_DECL const char *duk_push_string_tval_readable(duk_context *ctx, duk_tval *tv);
4891DUK_INTERNAL_DECL const char *duk_push_string_tval_readable_error(duk_context *ctx, duk_tval *tv);
4892
4893/* The duk_xxx_prop_stridx_short() variants expect their arguments to be short
4894 * enough to be packed into a single 32-bit integer argument. Argument limits
4895 * vary per call; typically 16 bits are assigned to the signed value stack index
4896 * and the stridx. In practice these work well for footprint with constant
4897 * arguments and such call sites are also easiest to verify to be correct.
4898 */
4899
4900DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [val] */
4901DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args);
4902#define duk_get_prop_stridx_short(ctx,obj_idx,stridx) \
4903 (DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x8000L && (duk_int_t) (obj_idx) <= 0x7fffL), \
4904 DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \
4905 duk_get_prop_stridx_short_raw((ctx), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
4906DUK_INTERNAL_DECL duk_bool_t duk_get_prop_stridx_boolean(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_bool_t *out_has_prop); /* [] -> [] */
4907
4908DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [val] -> [] */
4909DUK_INTERNAL_DECL duk_bool_t duk_put_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args);
4910#define duk_put_prop_stridx_short(ctx,obj_idx,stridx) \
4911 (DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x8000L && (duk_int_t) (obj_idx) <= 0x7fffL), \
4912 DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \
4913 duk_put_prop_stridx_short_raw((ctx), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
4914
4915DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */
4916#if 0 /* Too few call sites to be useful. */
4917DUK_INTERNAL_DECL duk_bool_t duk_del_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args);
4918#define duk_del_prop_stridx_short(ctx,obj_idx,stridx) \
4919 (DUK_ASSERT_EXPR((obj_idx) >= -0x8000L && (obj_idx) <= 0x7fffL), \
4920 DUK_ASSERT_EXPR((stridx) >= 0 && (stridx) <= 0xffffL), \
4921 duk_del_prop_stridx_short_raw((ctx), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
4922#endif
4923#define duk_del_prop_stridx_short(ctx,obj_idx,stridx) \
4924 duk_del_prop_stridx((ctx), (obj_idx), (stridx))
4925
4926DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */
4927#if 0 /* Too few call sites to be useful. */
4928DUK_INTERNAL_DECL duk_bool_t duk_has_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args);
4929#define duk_has_prop_stridx_short(ctx,obj_idx,stridx) \
4930 (DUK_ASSERT_EXPR((obj_idx) >= -0x8000L && (obj_idx) <= 0x7fffL), \
4931 DUK_ASSERT_EXPR((stridx) >= 0 && (stridx) <= 0xffffL), \
4932 duk_has_prop_stridx_short_raw((ctx), (((duk_uint_t) (obj_idx)) << 16) + ((duk_uint_t) (stridx))))
4933#endif
4934#define duk_has_prop_stridx_short(ctx,obj_idx,stridx) \
4935 duk_has_prop_stridx((ctx), (obj_idx), (stridx))
4936
4937DUK_INTERNAL_DECL void duk_xdef_prop(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t desc_flags); /* [key val] -> [] */
4938
4939DUK_INTERNAL_DECL void duk_xdef_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx, duk_small_uint_t desc_flags); /* [val] -> [] */
4940
4941/* XXX: Because stridx and desc_flags have a limited range, this call could
4942 * always pack stridx and desc_flags into a single argument.
4943 */
4944DUK_INTERNAL_DECL void duk_xdef_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_uint_t desc_flags); /* [val] -> [] */
4945DUK_INTERNAL_DECL void duk_xdef_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args);
4946#define duk_xdef_prop_stridx_short(ctx,obj_idx,stridx,desc_flags) \
4947 (DUK_ASSERT_EXPR((duk_int_t) (obj_idx) >= -0x80L && (duk_int_t) (obj_idx) <= 0x7fL), \
4948 DUK_ASSERT_EXPR((duk_int_t) (stridx) >= 0 && (duk_int_t) (stridx) <= 0xffffL), \
4949 DUK_ASSERT_EXPR((duk_int_t) (desc_flags) >= 0 && (duk_int_t) (desc_flags) <= 0xffL), \
4950 duk_xdef_prop_stridx_short_raw((ctx), (((duk_uint_t) (obj_idx)) << 24) + (((duk_uint_t) (stridx)) << 8) + (duk_uint_t) (desc_flags)))
4951
4952#define duk_xdef_prop_wec(ctx,obj_idx) \
4953 duk_xdef_prop((ctx), (obj_idx), DUK_PROPDESC_FLAGS_WEC)
4954#define duk_xdef_prop_index_wec(ctx,obj_idx,arr_idx) \
4955 duk_xdef_prop_index((ctx), (obj_idx), (arr_idx), DUK_PROPDESC_FLAGS_WEC)
4956#define duk_xdef_prop_stridx_wec(ctx,obj_idx,stridx) \
4957 duk_xdef_prop_stridx((ctx), (obj_idx), (stridx), DUK_PROPDESC_FLAGS_WEC)
4958#define duk_xdef_prop_stridx_short_wec(ctx,obj_idx,stridx) \
4959 duk_xdef_prop_stridx_short((ctx), (obj_idx), (stridx), DUK_PROPDESC_FLAGS_WEC)
4960
4961DUK_INTERNAL_DECL void duk_xdef_prop_stridx_builtin(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags); /* [] -> [] */
4962
4963DUK_INTERNAL_DECL void duk_xdef_prop_stridx_thrower(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx); /* [] -> [] */
4964
4965DUK_INTERNAL_DECL void duk_pack(duk_context *ctx, duk_idx_t count);
4966#if 0
4967DUK_INTERNAL_DECL void duk_unpack(duk_context *ctx);
4968#endif
4969
4970DUK_INTERNAL_DECL void duk_require_constructor_call(duk_context *ctx);
4971DUK_INTERNAL_DECL void duk_require_constructable(duk_context *ctx, duk_idx_t idx);
4972DUK_INTERNAL_DECL void duk_push_symbol_descriptive_string(duk_context *ctx, duk_hstring *h);
4973
4974DUK_INTERNAL_DECL void duk_resolve_nonbound_function(duk_context *ctx);
4975
4976DUK_INTERNAL_DECL duk_idx_t duk_get_top_require_min(duk_context *ctx, duk_idx_t min_top);
4977DUK_INTERNAL_DECL duk_idx_t duk_get_top_index_unsafe(duk_context *ctx);
4978DUK_INTERNAL_DECL void duk_pop_unsafe(duk_context *ctx);
4979
4980DUK_INTERNAL_DECL void duk_compact_m1(duk_context *ctx);
4981
4982/* Raw internal valstack access macros: access is unsafe so call site
4983 * must have a guarantee that the index is valid. When that is the case,
4984 * using these macro results in faster and smaller code than duk_get_tval().
4985 * Both 'ctx' and 'idx' are evaluted multiple times, but only for asserts.
4986 */
4987#define DUK_ASSERT_VALID_NEGIDX(ctx,idx) \
4988 (DUK_ASSERT_EXPR((duk_int_t) (idx) < 0), DUK_ASSERT_EXPR(duk_is_valid_index((ctx), (idx))))
4989#define DUK_ASSERT_VALID_POSIDX(ctx,idx) \
4990 (DUK_ASSERT_EXPR((duk_int_t) (idx) >= 0), DUK_ASSERT_EXPR(duk_is_valid_index((ctx), (idx))))
4991#define DUK_GET_TVAL_NEGIDX(ctx,idx) \
4992 (DUK_ASSERT_VALID_NEGIDX((ctx),(idx)), ((duk_hthread *) (ctx))->valstack_top + (idx))
4993#define DUK_GET_TVAL_POSIDX(ctx,idx) \
4994 (DUK_ASSERT_VALID_POSIDX((ctx),(idx)), ((duk_hthread *) (ctx))->valstack_bottom + (idx))
4995#define DUK_GET_HOBJECT_NEGIDX(ctx,idx) \
4996 (DUK_ASSERT_VALID_NEGIDX((ctx),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (ctx))->valstack_top + (idx)))
4997#define DUK_GET_HOBJECT_POSIDX(ctx,idx) \
4998 (DUK_ASSERT_VALID_POSIDX((ctx),(idx)), DUK_TVAL_GET_OBJECT(((duk_hthread *) (ctx))->valstack_bottom + (idx)))
4999
5000#define DUK_GET_THIS_TVAL_PTR(thr) \
5001 (DUK_ASSERT_EXPR((thr)->valstack_bottom > (thr)->valstack), \
5002 (thr)->valstack_bottom - 1)
5003
5004#endif /* DUK_API_INTERNAL_H_INCLUDED */
5005/* #include duk_hstring.h */
5006/*
5007 * Heap string representation.
5008 *
5009 * Strings are byte sequences ordinarily stored in extended UTF-8 format,
5010 * allowing values larger than the official UTF-8 range (used internally)
5011 * and also allowing UTF-8 encoding of surrogate pairs (CESU-8 format).
5012 * Strings may also be invalid UTF-8 altogether which is the case e.g. with
5013 * strings used as internal property names and raw buffers converted to
5014 * strings. In such cases the 'clen' field contains an inaccurate value.
5015 *
5016 * Ecmascript requires support for 32-bit long strings. However, since each
5017 * 16-bit codepoint can take 3 bytes in CESU-8, this representation can only
5018 * support about 1.4G codepoint long strings in extreme cases. This is not
5019 * really a practical issue.
5020 */
5021
5022#if !defined(DUK_HSTRING_H_INCLUDED)
5023#define DUK_HSTRING_H_INCLUDED
5024
5025/* Impose a maximum string length for now. Restricted artificially to
5026 * ensure adding a heap header length won't overflow size_t. The limit
5027 * should be synchronized with DUK_HBUFFER_MAX_BYTELEN.
5028 *
5029 * E5.1 makes provisions to support strings longer than 4G characters.
5030 * This limit should be eliminated on 64-bit platforms (and increased
5031 * closer to maximum support on 32-bit platforms).
5032 */
5033
5034#if defined(DUK_USE_STRLEN16)
5035#define DUK_HSTRING_MAX_BYTELEN (0x0000ffffUL)
5036#else
5037#define DUK_HSTRING_MAX_BYTELEN (0x7fffffffUL)
5038#endif
5039
5040/* XXX: could add flags for "is valid CESU-8" (Ecmascript compatible strings),
5041 * "is valid UTF-8", "is valid extended UTF-8" (internal strings are not,
5042 * regexp bytecode is), and "contains non-BMP characters". These are not
5043 * needed right now.
5044 */
5045
5046#define DUK_HSTRING_FLAG_ASCII DUK_HEAPHDR_USER_FLAG(0) /* string is ASCII, clen == blen */
5047#define DUK_HSTRING_FLAG_ARRIDX DUK_HEAPHDR_USER_FLAG(1) /* string is a valid array index */
5048#define DUK_HSTRING_FLAG_SYMBOL DUK_HEAPHDR_USER_FLAG(2) /* string is a symbol (invalid utf-8) */
5049#define DUK_HSTRING_FLAG_HIDDEN DUK_HEAPHDR_USER_FLAG(3) /* string is a hidden symbol (implies symbol, Duktape 1.x internal string) */
5050#define DUK_HSTRING_FLAG_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(4) /* string is a reserved word (non-strict) */
5051#define DUK_HSTRING_FLAG_STRICT_RESERVED_WORD DUK_HEAPHDR_USER_FLAG(5) /* string is a reserved word (strict) */
5052#define DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS DUK_HEAPHDR_USER_FLAG(6) /* string is 'eval' or 'arguments' */
5053#define DUK_HSTRING_FLAG_EXTDATA DUK_HEAPHDR_USER_FLAG(7) /* string data is external (duk_hstring_external) */
5054
5055#define DUK_HSTRING_HAS_ASCII(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII)
5056#define DUK_HSTRING_HAS_ARRIDX(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
5057#define DUK_HSTRING_HAS_SYMBOL(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_SYMBOL)
5058#define DUK_HSTRING_HAS_HIDDEN(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_HIDDEN)
5059#define DUK_HSTRING_HAS_RESERVED_WORD(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD)
5060#define DUK_HSTRING_HAS_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
5061#define DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
5062#define DUK_HSTRING_HAS_EXTDATA(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA)
5063
5064#define DUK_HSTRING_SET_ASCII(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII)
5065#define DUK_HSTRING_SET_ARRIDX(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
5066#define DUK_HSTRING_SET_SYMBOL(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_SYMBOL)
5067#define DUK_HSTRING_SET_HIDDEN(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_HIDDEN)
5068#define DUK_HSTRING_SET_RESERVED_WORD(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD)
5069#define DUK_HSTRING_SET_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
5070#define DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
5071#define DUK_HSTRING_SET_EXTDATA(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA)
5072
5073#define DUK_HSTRING_CLEAR_ASCII(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ASCII)
5074#define DUK_HSTRING_CLEAR_ARRIDX(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_ARRIDX)
5075#define DUK_HSTRING_CLEAR_SYMBOL(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_SYMBOL)
5076#define DUK_HSTRING_CLEAR_HIDDEN(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_HIDDEN)
5077#define DUK_HSTRING_CLEAR_RESERVED_WORD(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_RESERVED_WORD)
5078#define DUK_HSTRING_CLEAR_STRICT_RESERVED_WORD(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_STRICT_RESERVED_WORD)
5079#define DUK_HSTRING_CLEAR_EVAL_OR_ARGUMENTS(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS)
5080#define DUK_HSTRING_CLEAR_EXTDATA(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HSTRING_FLAG_EXTDATA)
5081
5082#if 0 /* Slightly smaller code without explicit flag, but explicit flag
5083 * is very useful when 'clen' is dropped.
5084 */
5085#define DUK_HSTRING_IS_ASCII(x) (DUK_HSTRING_GET_BYTELEN((x)) == DUK_HSTRING_GET_CHARLEN((x)))
5086#endif
5087#define DUK_HSTRING_IS_ASCII(x) DUK_HSTRING_HAS_ASCII((x))
5088#define DUK_HSTRING_IS_EMPTY(x) (DUK_HSTRING_GET_BYTELEN((x)) == 0)
5089
5090#if defined(DUK_USE_STRHASH16)
5091#define DUK_HSTRING_GET_HASH(x) ((x)->hdr.h_flags >> 16)
5092#define DUK_HSTRING_SET_HASH(x,v) do { \
5093 (x)->hdr.h_flags = ((x)->hdr.h_flags & 0x0000ffffUL) | ((v) << 16); \
5094 } while (0)
5095#else
5096#define DUK_HSTRING_GET_HASH(x) ((x)->hash)
5097#define DUK_HSTRING_SET_HASH(x,v) do { \
5098 (x)->hash = (v); \
5099 } while (0)
5100#endif
5101
5102#if defined(DUK_USE_STRLEN16)
5103#define DUK_HSTRING_GET_BYTELEN(x) ((x)->hdr.h_strextra16)
5104#define DUK_HSTRING_SET_BYTELEN(x,v) do { \
5105 (x)->hdr.h_strextra16 = (v); \
5106 } while (0)
5107#if defined(DUK_USE_HSTRING_CLEN)
5108#define DUK_HSTRING_GET_CHARLEN(x) ((x)->clen16)
5109#define DUK_HSTRING_SET_CHARLEN(x,v) do { \
5110 (x)->clen16 = (v); \
5111 } while (0)
5112#else
5113#define DUK_HSTRING_GET_CHARLEN(x) duk_hstring_get_charlen((x))
5114#define DUK_HSTRING_SET_CHARLEN(x,v) do { \
5115 DUK_ASSERT(0); /* should never be called */ \
5116 } while (0)
5117#endif
5118#else
5119#define DUK_HSTRING_GET_BYTELEN(x) ((x)->blen)
5120#define DUK_HSTRING_SET_BYTELEN(x,v) do { \
5121 (x)->blen = (v); \
5122 } while (0)
5123#define DUK_HSTRING_GET_CHARLEN(x) ((x)->clen)
5124#define DUK_HSTRING_SET_CHARLEN(x,v) do { \
5125 (x)->clen = (v); \
5126 } while (0)
5127#endif
5128
5129#if defined(DUK_USE_HSTRING_EXTDATA)
5130#define DUK_HSTRING_GET_EXTDATA(x) \
5131 ((x)->extdata)
5132#define DUK_HSTRING_GET_DATA(x) \
5133 (DUK_HSTRING_HAS_EXTDATA((x)) ? \
5134 DUK_HSTRING_GET_EXTDATA((const duk_hstring_external *) (x)) : ((const duk_uint8_t *) ((x) + 1)))
5135#else
5136#define DUK_HSTRING_GET_DATA(x) \
5137 ((const duk_uint8_t *) ((x) + 1))
5138#endif
5139
5140#define DUK_HSTRING_GET_DATA_END(x) \
5141 (DUK_HSTRING_GET_DATA((x)) + (x)->blen)
5142
5143/* marker value; in E5 2^32-1 is not a valid array index (2^32-2 is highest valid) */
5144#define DUK_HSTRING_NO_ARRAY_INDEX (0xffffffffUL)
5145
5146#if defined(DUK_USE_HSTRING_ARRIDX)
5147#define DUK_HSTRING_GET_ARRIDX_FAST(h) ((h)->arridx)
5148#define DUK_HSTRING_GET_ARRIDX_SLOW(h) ((h)->arridx)
5149#else
5150/* Get array index related to string (or return DUK_HSTRING_NO_ARRAY_INDEX);
5151 * avoids helper call if string has no array index value.
5152 */
5153#define DUK_HSTRING_GET_ARRIDX_FAST(h) \
5154 (DUK_HSTRING_HAS_ARRIDX((h)) ? duk_js_to_arrayindex_string_helper((h)) : DUK_HSTRING_NO_ARRAY_INDEX)
5155
5156/* Slower but more compact variant. */
5157#define DUK_HSTRING_GET_ARRIDX_SLOW(h) \
5158 (duk_js_to_arrayindex_string_helper((h)))
5159#endif
5160
5161/*
5162 * Misc
5163 */
5164
5166 /* Smaller heaphdr than for other objects, because strings are held
5167 * in string intern table which requires no link pointers. Much of
5168 * the 32-bit flags field is unused by flags, so we can stuff a 16-bit
5169 * field in there.
5170 */
5172
5173 /* Note: we could try to stuff a partial hash (e.g. 16 bits) into the
5174 * shared heap header. Good hashing needs more hash bits though.
5175 */
5176
5177 /* string hash */
5178#if defined(DUK_USE_STRHASH16)
5179 /* If 16-bit hash is in use, stuff it into duk_heaphdr_string flags. */
5180#else
5181 duk_uint32_t hash;
5182#endif
5183
5184 /* precomputed array index (or DUK_HSTRING_NO_ARRAY_INDEX) */
5185#if defined(DUK_USE_HSTRING_ARRIDX)
5186 duk_uarridx_t arridx;
5187#endif
5188
5189 /* length in bytes (not counting NUL term) */
5190#if defined(DUK_USE_STRLEN16)
5191 /* placed in duk_heaphdr_string */
5192#else
5193 duk_uint32_t blen;
5194#endif
5195
5196 /* length in codepoints (must be E5 compatible) */
5197#if defined(DUK_USE_STRLEN16)
5198#if defined(DUK_USE_HSTRING_CLEN)
5199 duk_uint16_t clen16;
5200#else
5201 /* computed live */
5202#endif
5203#else
5204 duk_uint32_t clen;
5205#endif
5206
5207 /*
5208 * String value of 'blen+1' bytes follows (+1 for NUL termination
5209 * convenience for C API). No alignment needs to be guaranteed
5210 * for strings, but fields above should guarantee alignment-by-4
5211 * (but not alignment-by-8).
5212 */
5213};
5214
5215/* The external string struct is defined even when the feature is inactive. */
5217 duk_hstring str;
5218
5219 /*
5220 * For an external string, the NUL-terminated string data is stored
5221 * externally. The user must guarantee that data behind this pointer
5222 * doesn't change while it's used.
5223 */
5224
5225 const duk_uint8_t *extdata;
5226};
5227
5228/*
5229 * Prototypes
5230 */
5231
5232DUK_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);
5233
5234#if !defined(DUK_USE_HSTRING_CLEN)
5235DUK_INTERNAL_DECL duk_size_t duk_hstring_get_charlen(duk_hstring *h);
5236#endif
5237
5238#endif /* DUK_HSTRING_H_INCLUDED */
5239/* #include duk_hobject.h */
5240/*
5241 * Heap object representation.
5242 *
5243 * Heap objects are used for Ecmascript objects, arrays, and functions,
5244 * but also for internal control like declarative and object environment
5245 * records. Compiled functions, native functions, and threads are also
5246 * objects but with an extended C struct.
5247 *
5248 * Objects provide the required Ecmascript semantics and exotic behaviors
5249 * especially for property access.
5250 *
5251 * Properties are stored in three conceptual parts:
5252 *
5253 * 1. A linear 'entry part' contains ordered key-value-attributes triples
5254 * and is the main method of string properties.
5255 *
5256 * 2. An optional linear 'array part' is used for array objects to store a
5257 * (dense) range of [0,N[ array indexed entries with default attributes
5258 * (writable, enumerable, configurable). If the array part would become
5259 * sparse or non-default attributes are required, the array part is
5260 * abandoned and moved to the 'entry part'.
5261 *
5262 * 3. An optional 'hash part' is used to optimize lookups of the entry
5263 * part; it is used only for objects with sufficiently many properties
5264 * and can be abandoned without loss of information.
5265 *
5266 * These three conceptual parts are stored in a single memory allocated area.
5267 * This minimizes memory allocation overhead but also means that all three
5268 * parts are resized together, and makes property access a bit complicated.
5269 */
5270
5271#if !defined(DUK_HOBJECT_H_INCLUDED)
5272#define DUK_HOBJECT_H_INCLUDED
5273
5274/* Object flag. There are currently 25 flag bits available. Make sure
5275 * this stays in sync with debugger object inspection code.
5276 */
5277
5278/* XXX: some flags are object subtype specific (e.g. common to all function
5279 * subtypes, duk_harray, etc) and could be reused for different subtypes.
5280 */
5281#define DUK_HOBJECT_FLAG_EXTENSIBLE DUK_HEAPHDR_USER_FLAG(0) /* object is extensible */
5282#define DUK_HOBJECT_FLAG_CONSTRUCTABLE DUK_HEAPHDR_USER_FLAG(1) /* object is constructable */
5283#define DUK_HOBJECT_FLAG_BOUNDFUNC DUK_HEAPHDR_USER_FLAG(2) /* object established using Function.prototype.bind() */
5284#define DUK_HOBJECT_FLAG_COMPFUNC DUK_HEAPHDR_USER_FLAG(4) /* object is a compiled function (duk_hcompfunc) */
5285#define DUK_HOBJECT_FLAG_NATFUNC DUK_HEAPHDR_USER_FLAG(5) /* object is a native function (duk_hnatfunc) */
5286#define DUK_HOBJECT_FLAG_BUFOBJ DUK_HEAPHDR_USER_FLAG(6) /* object is a buffer object (duk_hbufobj) (always exotic) */
5287#define DUK_HOBJECT_FLAG_THREAD DUK_HEAPHDR_USER_FLAG(7) /* object is a thread (duk_hthread) */
5288#define DUK_HOBJECT_FLAG_ARRAY_PART DUK_HEAPHDR_USER_FLAG(8) /* object has an array part (a_size may still be 0) */
5289#define DUK_HOBJECT_FLAG_STRICT DUK_HEAPHDR_USER_FLAG(9) /* function: function object is strict */
5290#define DUK_HOBJECT_FLAG_NOTAIL DUK_HEAPHDR_USER_FLAG(10) /* function: function must not be tail called */
5291#define DUK_HOBJECT_FLAG_NEWENV DUK_HEAPHDR_USER_FLAG(11) /* function: create new environment when called (see duk_hcompfunc) */
5292#define DUK_HOBJECT_FLAG_NAMEBINDING DUK_HEAPHDR_USER_FLAG(12) /* function: create binding for func name (function templates only, used for named function expressions) */
5293#define DUK_HOBJECT_FLAG_CREATEARGS DUK_HEAPHDR_USER_FLAG(13) /* function: create an arguments object on function call */
5294#define DUK_HOBJECT_FLAG_ENVRECCLOSED DUK_HEAPHDR_USER_FLAG(14) /* envrec: (declarative) record is closed */
5295#define DUK_HOBJECT_FLAG_EXOTIC_ARRAY DUK_HEAPHDR_USER_FLAG(15) /* 'Array' object, array length and index exotic behavior */
5296#define DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ DUK_HEAPHDR_USER_FLAG(16) /* 'String' object, array index exotic behavior */
5297#define DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS DUK_HEAPHDR_USER_FLAG(17) /* 'Arguments' object and has arguments exotic behavior (non-strict callee) */
5298#define DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC DUK_HEAPHDR_USER_FLAG(18) /* Duktape/C (nativefunction) object, exotic 'length' */
5299#define DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ DUK_HEAPHDR_USER_FLAG(19) /* 'Proxy' object */
5300
5301#define DUK_HOBJECT_FLAG_CLASS_BASE DUK_HEAPHDR_USER_FLAG_NUMBER(20)
5302#define DUK_HOBJECT_FLAG_CLASS_BITS 5
5303
5304#define DUK_HOBJECT_GET_CLASS_NUMBER(h) \
5305 DUK_HEAPHDR_GET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS)
5306#define DUK_HOBJECT_SET_CLASS_NUMBER(h,v) \
5307 DUK_HEAPHDR_SET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS, (v))
5308
5309#define DUK_HOBJECT_GET_CLASS_MASK(h) \
5310 (1UL << DUK_HEAPHDR_GET_FLAG_RANGE(&(h)->hdr, DUK_HOBJECT_FLAG_CLASS_BASE, DUK_HOBJECT_FLAG_CLASS_BITS))
5311
5312/* Macro for creating flag initializer from a class number.
5313 * Unsigned type cast is needed to avoid warnings about coercing
5314 * a signed integer to an unsigned one; the largest class values
5315 * have the highest bit (bit 31) set which causes this.
5316 */
5317#define DUK_HOBJECT_CLASS_AS_FLAGS(v) (((duk_uint_t) (v)) << DUK_HOBJECT_FLAG_CLASS_BASE)
5318
5319/* E5 Section 8.6.2 + custom classes */
5320#define DUK_HOBJECT_CLASS_NONE 0
5321#define DUK_HOBJECT_CLASS_OBJECT 1
5322#define DUK_HOBJECT_CLASS_ARRAY 2
5323#define DUK_HOBJECT_CLASS_FUNCTION 3
5324#define DUK_HOBJECT_CLASS_ARGUMENTS 4
5325#define DUK_HOBJECT_CLASS_BOOLEAN 5
5326#define DUK_HOBJECT_CLASS_DATE 6
5327#define DUK_HOBJECT_CLASS_ERROR 7
5328#define DUK_HOBJECT_CLASS_JSON 8
5329#define DUK_HOBJECT_CLASS_MATH 9
5330#define DUK_HOBJECT_CLASS_NUMBER 10
5331#define DUK_HOBJECT_CLASS_REGEXP 11
5332#define DUK_HOBJECT_CLASS_STRING 12
5333#define DUK_HOBJECT_CLASS_GLOBAL 13
5334#define DUK_HOBJECT_CLASS_SYMBOL 14
5335#define DUK_HOBJECT_CLASS_OBJENV 15 /* custom */
5336#define DUK_HOBJECT_CLASS_DECENV 16 /* custom */
5337#define DUK_HOBJECT_CLASS_POINTER 17 /* custom */
5338#define DUK_HOBJECT_CLASS_THREAD 18 /* custom; implies DUK_HOBJECT_IS_THREAD */
5339#define DUK_HOBJECT_CLASS_BUFOBJ_MIN 19
5340#define DUK_HOBJECT_CLASS_ARRAYBUFFER 19 /* implies DUK_HOBJECT_IS_BUFOBJ */
5341#define DUK_HOBJECT_CLASS_DATAVIEW 20
5342#define DUK_HOBJECT_CLASS_INT8ARRAY 21
5343#define DUK_HOBJECT_CLASS_UINT8ARRAY 22
5344#define DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY 23
5345#define DUK_HOBJECT_CLASS_INT16ARRAY 24
5346#define DUK_HOBJECT_CLASS_UINT16ARRAY 25
5347#define DUK_HOBJECT_CLASS_INT32ARRAY 26
5348#define DUK_HOBJECT_CLASS_UINT32ARRAY 27
5349#define DUK_HOBJECT_CLASS_FLOAT32ARRAY 28
5350#define DUK_HOBJECT_CLASS_FLOAT64ARRAY 29
5351#define DUK_HOBJECT_CLASS_BUFOBJ_MAX 29
5352#define DUK_HOBJECT_CLASS_MAX 29
5353
5354/* Class masks. */
5355#define DUK_HOBJECT_CMASK_ALL ((1UL << (DUK_HOBJECT_CLASS_MAX + 1)) - 1UL)
5356#define DUK_HOBJECT_CMASK_NONE (1UL << DUK_HOBJECT_CLASS_NONE)
5357#define DUK_HOBJECT_CMASK_ARGUMENTS (1UL << DUK_HOBJECT_CLASS_ARGUMENTS)
5358#define DUK_HOBJECT_CMASK_ARRAY (1UL << DUK_HOBJECT_CLASS_ARRAY)
5359#define DUK_HOBJECT_CMASK_BOOLEAN (1UL << DUK_HOBJECT_CLASS_BOOLEAN)
5360#define DUK_HOBJECT_CMASK_DATE (1UL << DUK_HOBJECT_CLASS_DATE)
5361#define DUK_HOBJECT_CMASK_ERROR (1UL << DUK_HOBJECT_CLASS_ERROR)
5362#define DUK_HOBJECT_CMASK_FUNCTION (1UL << DUK_HOBJECT_CLASS_FUNCTION)
5363#define DUK_HOBJECT_CMASK_JSON (1UL << DUK_HOBJECT_CLASS_JSON)
5364#define DUK_HOBJECT_CMASK_MATH (1UL << DUK_HOBJECT_CLASS_MATH)
5365#define DUK_HOBJECT_CMASK_NUMBER (1UL << DUK_HOBJECT_CLASS_NUMBER)
5366#define DUK_HOBJECT_CMASK_OBJECT (1UL << DUK_HOBJECT_CLASS_OBJECT)
5367#define DUK_HOBJECT_CMASK_REGEXP (1UL << DUK_HOBJECT_CLASS_REGEXP)
5368#define DUK_HOBJECT_CMASK_STRING (1UL << DUK_HOBJECT_CLASS_STRING)
5369#define DUK_HOBJECT_CMASK_GLOBAL (1UL << DUK_HOBJECT_CLASS_GLOBAL)
5370#define DUK_HOBJECT_CMASK_SYMBOL (1UL << DUK_HOBJECT_CLASS_SYMBOL)
5371#define DUK_HOBJECT_CMASK_OBJENV (1UL << DUK_HOBJECT_CLASS_OBJENV)
5372#define DUK_HOBJECT_CMASK_DECENV (1UL << DUK_HOBJECT_CLASS_DECENV)
5373#define DUK_HOBJECT_CMASK_POINTER (1UL << DUK_HOBJECT_CLASS_POINTER)
5374#define DUK_HOBJECT_CMASK_THREAD (1UL << DUK_HOBJECT_CLASS_THREAD)
5375#define DUK_HOBJECT_CMASK_ARRAYBUFFER (1UL << DUK_HOBJECT_CLASS_ARRAYBUFFER)
5376#define DUK_HOBJECT_CMASK_DATAVIEW (1UL << DUK_HOBJECT_CLASS_DATAVIEW)
5377#define DUK_HOBJECT_CMASK_INT8ARRAY (1UL << DUK_HOBJECT_CLASS_INT8ARRAY)
5378#define DUK_HOBJECT_CMASK_UINT8ARRAY (1UL << DUK_HOBJECT_CLASS_UINT8ARRAY)
5379#define DUK_HOBJECT_CMASK_UINT8CLAMPEDARRAY (1UL << DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY)
5380#define DUK_HOBJECT_CMASK_INT16ARRAY (1UL << DUK_HOBJECT_CLASS_INT16ARRAY)
5381#define DUK_HOBJECT_CMASK_UINT16ARRAY (1UL << DUK_HOBJECT_CLASS_UINT16ARRAY)
5382#define DUK_HOBJECT_CMASK_INT32ARRAY (1UL << DUK_HOBJECT_CLASS_INT32ARRAY)
5383#define DUK_HOBJECT_CMASK_UINT32ARRAY (1UL << DUK_HOBJECT_CLASS_UINT32ARRAY)
5384#define DUK_HOBJECT_CMASK_FLOAT32ARRAY (1UL << DUK_HOBJECT_CLASS_FLOAT32ARRAY)
5385#define DUK_HOBJECT_CMASK_FLOAT64ARRAY (1UL << DUK_HOBJECT_CLASS_FLOAT64ARRAY)
5386
5387#define DUK_HOBJECT_CMASK_ALL_BUFOBJS \
5388 (DUK_HOBJECT_CMASK_ARRAYBUFFER | \
5389 DUK_HOBJECT_CMASK_DATAVIEW | \
5390 DUK_HOBJECT_CMASK_INT8ARRAY | \
5391 DUK_HOBJECT_CMASK_UINT8ARRAY | \
5392 DUK_HOBJECT_CMASK_UINT8CLAMPEDARRAY | \
5393 DUK_HOBJECT_CMASK_INT16ARRAY | \
5394 DUK_HOBJECT_CMASK_UINT16ARRAY | \
5395 DUK_HOBJECT_CMASK_INT32ARRAY | \
5396 DUK_HOBJECT_CMASK_UINT32ARRAY | \
5397 DUK_HOBJECT_CMASK_FLOAT32ARRAY | \
5398 DUK_HOBJECT_CMASK_FLOAT64ARRAY)
5399
5400#define DUK_HOBJECT_IS_OBJENV(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_OBJENV)
5401#define DUK_HOBJECT_IS_DECENV(h) (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_DECENV)
5402#define DUK_HOBJECT_IS_ENV(h) (DUK_HOBJECT_IS_OBJENV((h)) || DUK_HOBJECT_IS_DECENV((h)))
5403#define DUK_HOBJECT_IS_ARRAY(h) DUK_HOBJECT_HAS_EXOTIC_ARRAY((h)) /* Rely on class Array <=> exotic Array */
5404#define DUK_HOBJECT_IS_BOUNDFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
5405#define DUK_HOBJECT_IS_COMPFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
5406#define DUK_HOBJECT_IS_NATFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
5407#define DUK_HOBJECT_IS_BUFOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
5408#define DUK_HOBJECT_IS_THREAD(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
5409
5410#define DUK_HOBJECT_IS_NONBOUND_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
5411 DUK_HOBJECT_FLAG_COMPFUNC | \
5412 DUK_HOBJECT_FLAG_NATFUNC)
5413
5414#define DUK_HOBJECT_IS_FUNCTION(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
5415 DUK_HOBJECT_FLAG_BOUNDFUNC | \
5416 DUK_HOBJECT_FLAG_COMPFUNC | \
5417 DUK_HOBJECT_FLAG_NATFUNC)
5418
5419#define DUK_HOBJECT_IS_CALLABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, \
5420 DUK_HOBJECT_FLAG_BOUNDFUNC | \
5421 DUK_HOBJECT_FLAG_COMPFUNC | \
5422 DUK_HOBJECT_FLAG_NATFUNC)
5423
5424/* Object has any exotic behavior(s). */
5425#define DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS (DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \
5426 DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS | \
5427 DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | \
5428 DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC | \
5429 DUK_HOBJECT_FLAG_BUFOBJ | \
5430 DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
5431#define DUK_HOBJECT_HAS_EXOTIC_BEHAVIOR(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_EXOTIC_BEHAVIOR_FLAGS)
5432
5433/* Object has any virtual properties (not counting Proxy behavior). */
5434#define DUK_HOBJECT_VIRTUAL_PROPERTY_FLAGS (DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \
5435 DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ | \
5436 DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC | \
5437 DUK_HOBJECT_FLAG_BUFOBJ)
5438#define DUK_HOBJECT_HAS_VIRTUAL_PROPERTIES(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_VIRTUAL_PROPERTY_FLAGS)
5439
5440#define DUK_HOBJECT_HAS_EXTENSIBLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
5441#define DUK_HOBJECT_HAS_CONSTRUCTABLE(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
5442#define DUK_HOBJECT_HAS_BOUNDFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
5443#define DUK_HOBJECT_HAS_COMPFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
5444#define DUK_HOBJECT_HAS_NATFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
5445#define DUK_HOBJECT_HAS_BUFOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
5446#define DUK_HOBJECT_HAS_THREAD(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
5447#define DUK_HOBJECT_HAS_ARRAY_PART(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
5448#define DUK_HOBJECT_HAS_STRICT(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
5449#define DUK_HOBJECT_HAS_NOTAIL(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
5450#define DUK_HOBJECT_HAS_NEWENV(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
5451#define DUK_HOBJECT_HAS_NAMEBINDING(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
5452#define DUK_HOBJECT_HAS_CREATEARGS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
5453#define DUK_HOBJECT_HAS_ENVRECCLOSED(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED)
5454#define DUK_HOBJECT_HAS_EXOTIC_ARRAY(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
5455#define DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
5456#define DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
5457#define DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC)
5458#define DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CHECK_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
5459
5460#define DUK_HOBJECT_SET_EXTENSIBLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
5461#define DUK_HOBJECT_SET_CONSTRUCTABLE(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
5462#define DUK_HOBJECT_SET_BOUNDFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
5463#define DUK_HOBJECT_SET_COMPFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
5464#define DUK_HOBJECT_SET_NATFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
5465#define DUK_HOBJECT_SET_BUFOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
5466#define DUK_HOBJECT_SET_THREAD(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
5467#define DUK_HOBJECT_SET_ARRAY_PART(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
5468#define DUK_HOBJECT_SET_STRICT(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
5469#define DUK_HOBJECT_SET_NOTAIL(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
5470#define DUK_HOBJECT_SET_NEWENV(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
5471#define DUK_HOBJECT_SET_NAMEBINDING(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
5472#define DUK_HOBJECT_SET_CREATEARGS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
5473#define DUK_HOBJECT_SET_ENVRECCLOSED(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED)
5474#define DUK_HOBJECT_SET_EXOTIC_ARRAY(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
5475#define DUK_HOBJECT_SET_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
5476#define DUK_HOBJECT_SET_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
5477#define DUK_HOBJECT_SET_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC)
5478#define DUK_HOBJECT_SET_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_SET_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
5479
5480#define DUK_HOBJECT_CLEAR_EXTENSIBLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXTENSIBLE)
5481#define DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CONSTRUCTABLE)
5482#define DUK_HOBJECT_CLEAR_BOUNDFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BOUNDFUNC)
5483#define DUK_HOBJECT_CLEAR_COMPFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_COMPFUNC)
5484#define DUK_HOBJECT_CLEAR_NATFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NATFUNC)
5485#define DUK_HOBJECT_CLEAR_BUFOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_BUFOBJ)
5486#define DUK_HOBJECT_CLEAR_THREAD(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_THREAD)
5487#define DUK_HOBJECT_CLEAR_ARRAY_PART(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ARRAY_PART)
5488#define DUK_HOBJECT_CLEAR_STRICT(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_STRICT)
5489#define DUK_HOBJECT_CLEAR_NOTAIL(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NOTAIL)
5490#define DUK_HOBJECT_CLEAR_NEWENV(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NEWENV)
5491#define DUK_HOBJECT_CLEAR_NAMEBINDING(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_NAMEBINDING)
5492#define DUK_HOBJECT_CLEAR_CREATEARGS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_CREATEARGS)
5493#define DUK_HOBJECT_CLEAR_ENVRECCLOSED(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_ENVRECCLOSED)
5494#define DUK_HOBJECT_CLEAR_EXOTIC_ARRAY(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARRAY)
5495#define DUK_HOBJECT_CLEAR_EXOTIC_STRINGOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ)
5496#define DUK_HOBJECT_CLEAR_EXOTIC_ARGUMENTS(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS)
5497#define DUK_HOBJECT_CLEAR_EXOTIC_DUKFUNC(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC)
5498#define DUK_HOBJECT_CLEAR_EXOTIC_PROXYOBJ(h) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(h)->hdr, DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ)
5499
5500/* Flags used for property attributes in duk_propdesc and packed flags.
5501 * Must fit into 8 bits.
5502 */
5503#define DUK_PROPDESC_FLAG_WRITABLE (1 << 0) /* E5 Section 8.6.1 */
5504#define DUK_PROPDESC_FLAG_ENUMERABLE (1 << 1) /* E5 Section 8.6.1 */
5505#define DUK_PROPDESC_FLAG_CONFIGURABLE (1 << 2) /* E5 Section 8.6.1 */
5506#define DUK_PROPDESC_FLAG_ACCESSOR (1 << 3) /* accessor */
5507#define DUK_PROPDESC_FLAG_VIRTUAL (1 << 4) /* property is virtual: used in duk_propdesc, never stored
5508 * (used by e.g. buffer virtual properties)
5509 */
5510#define DUK_PROPDESC_FLAGS_MASK (DUK_PROPDESC_FLAG_WRITABLE | \
5511 DUK_PROPDESC_FLAG_ENUMERABLE | \
5512 DUK_PROPDESC_FLAG_CONFIGURABLE | \
5513 DUK_PROPDESC_FLAG_ACCESSOR)
5514
5515/* Additional flags which are passed in the same flags argument as property
5516 * flags but are not stored in object properties.
5517 */
5518#define DUK_PROPDESC_FLAG_NO_OVERWRITE (1 << 4) /* internal define property: skip write silently if exists */
5519
5520/* Convenience defines for property attributes. */
5521#define DUK_PROPDESC_FLAGS_NONE 0
5522#define DUK_PROPDESC_FLAGS_W (DUK_PROPDESC_FLAG_WRITABLE)
5523#define DUK_PROPDESC_FLAGS_E (DUK_PROPDESC_FLAG_ENUMERABLE)
5524#define DUK_PROPDESC_FLAGS_C (DUK_PROPDESC_FLAG_CONFIGURABLE)
5525#define DUK_PROPDESC_FLAGS_WE (DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_ENUMERABLE)
5526#define DUK_PROPDESC_FLAGS_WC (DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_CONFIGURABLE)
5527#define DUK_PROPDESC_FLAGS_EC (DUK_PROPDESC_FLAG_ENUMERABLE | DUK_PROPDESC_FLAG_CONFIGURABLE)
5528#define DUK_PROPDESC_FLAGS_WEC (DUK_PROPDESC_FLAG_WRITABLE | \
5529 DUK_PROPDESC_FLAG_ENUMERABLE | \
5530 DUK_PROPDESC_FLAG_CONFIGURABLE)
5531
5532/* Flags for duk_hobject_get_own_propdesc() and variants. */
5533#define DUK_GETDESC_FLAG_PUSH_VALUE (1 << 0) /* push value to stack */
5534#define DUK_GETDESC_FLAG_IGNORE_PROTOLOOP (1 << 1) /* don't throw for prototype loop */
5535
5536/*
5537 * Macro for object validity check
5538 *
5539 * Assert for currently guaranteed relations between flags, for instance.
5540 */
5541
5542#define DUK_ASSERT_HOBJECT_VALID(h) do { \
5543 DUK_ASSERT((h) != NULL); \
5544 DUK_ASSERT(!DUK_HOBJECT_IS_CALLABLE((h)) || \
5545 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FUNCTION); \
5546 DUK_ASSERT(!DUK_HOBJECT_IS_BUFOBJ((h)) || \
5547 (DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAYBUFFER || \
5548 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_DATAVIEW || \
5549 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_INT8ARRAY || \
5550 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT8ARRAY || \
5551 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY || \
5552 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_INT16ARRAY || \
5553 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT16ARRAY || \
5554 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_INT32ARRAY || \
5555 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_UINT32ARRAY || \
5556 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FLOAT32ARRAY || \
5557 DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_FLOAT64ARRAY)); \
5558 /* Object is an Array <=> object has exotic array behavior */ \
5559 DUK_ASSERT((DUK_HOBJECT_GET_CLASS_NUMBER((h)) == DUK_HOBJECT_CLASS_ARRAY && DUK_HOBJECT_HAS_EXOTIC_ARRAY((h))) || \
5560 (DUK_HOBJECT_GET_CLASS_NUMBER((h)) != DUK_HOBJECT_CLASS_ARRAY && !DUK_HOBJECT_HAS_EXOTIC_ARRAY((h)))); \
5561 } while (0)
5562
5563/*
5564 * Macros to access the 'props' allocation.
5565 */
5566
5567#if defined(DUK_USE_HEAPPTR16)
5568#define DUK_HOBJECT_GET_PROPS(heap,h) \
5569 ((duk_uint8_t *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, ((duk_heaphdr *) (h))->h_extra16))
5570#define DUK_HOBJECT_SET_PROPS(heap,h,x) do { \
5571 ((duk_heaphdr *) (h))->h_extra16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (x)); \
5572 } while (0)
5573#else
5574#define DUK_HOBJECT_GET_PROPS(heap,h) \
5575 ((h)->props)
5576#define DUK_HOBJECT_SET_PROPS(heap,h,x) do { \
5577 (h)->props = (duk_uint8_t *) (x); \
5578 } while (0)
5579#endif
5580
5581#if defined(DUK_USE_HOBJECT_LAYOUT_1)
5582/* LAYOUT 1 */
5583#define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \
5584 ((duk_hstring **) (void *) ( \
5585 DUK_HOBJECT_GET_PROPS((heap), (h)) \
5586 ))
5587#define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \
5588 ((duk_propvalue *) (void *) ( \
5589 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
5590 DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_hstring *) \
5591 ))
5592#define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \
5593 ((duk_uint8_t *) (void *) ( \
5594 DUK_HOBJECT_GET_PROPS((heap), (h)) + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue)) \
5595 ))
5596#define DUK_HOBJECT_A_GET_BASE(heap,h) \
5597 ((duk_tval *) (void *) ( \
5598 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
5599 DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) \
5600 ))
5601#define DUK_HOBJECT_H_GET_BASE(heap,h) \
5602 ((duk_uint32_t *) (void *) ( \
5603 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
5604 DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
5605 DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
5606 ))
5607#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \
5608 ( \
5609 (n_ent) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
5610 (n_arr) * sizeof(duk_tval) + \
5611 (n_hash) * sizeof(duk_uint32_t) \
5612 )
5613#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 { \
5614 (set_e_k) = (duk_hstring **) (void *) (p_base); \
5615 (set_e_pv) = (duk_propvalue *) (void *) ((set_e_k) + (n_ent)); \
5616 (set_e_f) = (duk_uint8_t *) (void *) ((set_e_pv) + (n_ent)); \
5617 (set_a) = (duk_tval *) (void *) ((set_e_f) + (n_ent)); \
5618 (set_h) = (duk_uint32_t *) (void *) ((set_a) + (n_arr)); \
5619 } while (0)
5620#elif defined(DUK_USE_HOBJECT_LAYOUT_2)
5621/* LAYOUT 2 */
5622#if (DUK_USE_ALIGN_BY == 4)
5623#define DUK_HOBJECT_E_FLAG_PADDING(e_sz) ((4 - (e_sz)) & 0x03)
5624#elif (DUK_USE_ALIGN_BY == 8)
5625#define DUK_HOBJECT_E_FLAG_PADDING(e_sz) ((8 - (e_sz)) & 0x07)
5626#elif (DUK_USE_ALIGN_BY == 1)
5627#define DUK_HOBJECT_E_FLAG_PADDING(e_sz) 0
5628#else
5629#error invalid DUK_USE_ALIGN_BY
5630#endif
5631#define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \
5632 ((duk_hstring **) (void *) ( \
5633 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
5634 DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) \
5635 ))
5636#define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \
5637 ((duk_propvalue *) (void *) ( \
5638 DUK_HOBJECT_GET_PROPS((heap), (h)) \
5639 ))
5640#define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \
5641 ((duk_uint8_t *) (void *) ( \
5642 DUK_HOBJECT_GET_PROPS((heap), (h)) + DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue)) \
5643 ))
5644#define DUK_HOBJECT_A_GET_BASE(heap,h) \
5645 ((duk_tval *) (void *) ( \
5646 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
5647 DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
5648 DUK_HOBJECT_E_FLAG_PADDING(DUK_HOBJECT_GET_ESIZE((h))) \
5649 ))
5650#define DUK_HOBJECT_H_GET_BASE(heap,h) \
5651 ((duk_uint32_t *) (void *) ( \
5652 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
5653 DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
5654 DUK_HOBJECT_E_FLAG_PADDING(DUK_HOBJECT_GET_ESIZE((h))) + \
5655 DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
5656 ))
5657#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \
5658 ( \
5659 (n_ent) * (sizeof(duk_hstring *) + sizeof(duk_propvalue) + sizeof(duk_uint8_t)) + \
5660 DUK_HOBJECT_E_FLAG_PADDING((n_ent)) + \
5661 (n_arr) * sizeof(duk_tval) + \
5662 (n_hash) * sizeof(duk_uint32_t) \
5663 )
5664#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 { \
5665 (set_e_pv) = (duk_propvalue *) (void *) (p_base); \
5666 (set_e_k) = (duk_hstring **) (void *) ((set_e_pv) + (n_ent)); \
5667 (set_e_f) = (duk_uint8_t *) (void *) ((set_e_k) + (n_ent)); \
5668 (set_a) = (duk_tval *) (void *) (((duk_uint8_t *) (set_e_f)) + \
5669 sizeof(duk_uint8_t) * (n_ent) + \
5670 DUK_HOBJECT_E_FLAG_PADDING((n_ent))); \
5671 (set_h) = (duk_uint32_t *) (void *) ((set_a) + (n_arr)); \
5672 } while (0)
5673#elif defined(DUK_USE_HOBJECT_LAYOUT_3)
5674/* LAYOUT 3 */
5675#define DUK_HOBJECT_E_GET_KEY_BASE(heap,h) \
5676 ((duk_hstring **) (void *) ( \
5677 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
5678 DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) + \
5679 DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
5680 ))
5681#define DUK_HOBJECT_E_GET_VALUE_BASE(heap,h) \
5682 ((duk_propvalue *) (void *) ( \
5683 DUK_HOBJECT_GET_PROPS((heap), (h)) \
5684 ))
5685#define DUK_HOBJECT_E_GET_FLAGS_BASE(heap,h) \
5686 ((duk_uint8_t *) (void *) ( \
5687 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
5688 DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_propvalue) + sizeof(duk_hstring *)) + \
5689 DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) + \
5690 DUK_HOBJECT_GET_HSIZE((h)) * sizeof(duk_uint32_t) \
5691 ))
5692#define DUK_HOBJECT_A_GET_BASE(heap,h) \
5693 ((duk_tval *) (void *) ( \
5694 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
5695 DUK_HOBJECT_GET_ESIZE((h)) * sizeof(duk_propvalue) \
5696 ))
5697#define DUK_HOBJECT_H_GET_BASE(heap,h) \
5698 ((duk_uint32_t *) (void *) ( \
5699 DUK_HOBJECT_GET_PROPS((heap), (h)) + \
5700 DUK_HOBJECT_GET_ESIZE((h)) * (sizeof(duk_propvalue) + sizeof(duk_hstring *)) + \
5701 DUK_HOBJECT_GET_ASIZE((h)) * sizeof(duk_tval) \
5702 ))
5703#define DUK_HOBJECT_P_COMPUTE_SIZE(n_ent,n_arr,n_hash) \
5704 ( \
5705 (n_ent) * (sizeof(duk_propvalue) + sizeof(duk_hstring *) + sizeof(duk_uint8_t)) + \
5706 (n_arr) * sizeof(duk_tval) + \
5707 (n_hash) * sizeof(duk_uint32_t) \
5708 )
5709#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 { \
5710 (set_e_pv) = (duk_propvalue *) (void *) (p_base); \
5711 (set_a) = (duk_tval *) (void *) ((set_e_pv) + (n_ent)); \
5712 (set_e_k) = (duk_hstring **) (void *) ((set_a) + (n_arr)); \
5713 (set_h) = (duk_uint32_t *) (void *) ((set_e_k) + (n_ent)); \
5714 (set_e_f) = (duk_uint8_t *) (void *) ((set_h) + (n_hash)); \
5715 } while (0)
5716#else
5717#error invalid hobject layout defines
5718#endif /* hobject property layout */
5719
5720#define DUK_HOBJECT_P_ALLOC_SIZE(h) \
5721 DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE((h)), DUK_HOBJECT_GET_ASIZE((h)), DUK_HOBJECT_GET_HSIZE((h)))
5722
5723#define DUK_HOBJECT_E_GET_KEY(heap,h,i) (DUK_HOBJECT_E_GET_KEY_BASE((heap), (h))[(i)])
5724#define DUK_HOBJECT_E_GET_KEY_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_KEY_BASE((heap), (h))[(i)])
5725#define DUK_HOBJECT_E_GET_VALUE(heap,h,i) (DUK_HOBJECT_E_GET_VALUE_BASE((heap), (h))[(i)])
5726#define DUK_HOBJECT_E_GET_VALUE_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE_BASE((heap), (h))[(i)])
5727#define DUK_HOBJECT_E_GET_VALUE_TVAL(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v)
5728#define DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v)
5729#define DUK_HOBJECT_E_GET_VALUE_GETTER(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get)
5730#define DUK_HOBJECT_E_GET_VALUE_GETTER_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get)
5731#define DUK_HOBJECT_E_GET_VALUE_SETTER(heap,h,i) (DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set)
5732#define DUK_HOBJECT_E_GET_VALUE_SETTER_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set)
5733#define DUK_HOBJECT_E_GET_FLAGS(heap,h,i) (DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)])
5734#define DUK_HOBJECT_E_GET_FLAGS_PTR(heap,h,i) (&DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)])
5735#define DUK_HOBJECT_A_GET_VALUE(heap,h,i) (DUK_HOBJECT_A_GET_BASE((heap), (h))[(i)])
5736#define DUK_HOBJECT_A_GET_VALUE_PTR(heap,h,i) (&DUK_HOBJECT_A_GET_BASE((heap), (h))[(i)])
5737#define DUK_HOBJECT_H_GET_INDEX(heap,h,i) (DUK_HOBJECT_H_GET_BASE((heap), (h))[(i)])
5738#define DUK_HOBJECT_H_GET_INDEX_PTR(heap,h,i) (&DUK_HOBJECT_H_GET_BASE((heap), (h))[(i)])
5739
5740#define DUK_HOBJECT_E_SET_KEY(heap,h,i,k) do { \
5741 DUK_HOBJECT_E_GET_KEY((heap), (h), (i)) = (k); \
5742 } while (0)
5743#define DUK_HOBJECT_E_SET_VALUE(heap,h,i,v) do { \
5744 DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)) = (v); \
5745 } while (0)
5746#define DUK_HOBJECT_E_SET_VALUE_TVAL(heap,h,i,v) do { \
5747 DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).v = (v); \
5748 } while (0)
5749#define DUK_HOBJECT_E_SET_VALUE_GETTER(heap,h,i,v) do { \
5750 DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.get = (v); \
5751 } while (0)
5752#define DUK_HOBJECT_E_SET_VALUE_SETTER(heap,h,i,v) do { \
5753 DUK_HOBJECT_E_GET_VALUE((heap), (h), (i)).a.set = (v); \
5754 } while (0)
5755#define DUK_HOBJECT_E_SET_FLAGS(heap,h,i,f) do { \
5756 DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) = (duk_uint8_t) (f); \
5757 } while (0)
5758#define DUK_HOBJECT_A_SET_VALUE(heap,h,i,v) do { \
5759 DUK_HOBJECT_A_GET_VALUE((heap), (h), (i)) = (v); \
5760 } while (0)
5761#define DUK_HOBJECT_A_SET_VALUE_TVAL(heap,h,i,v) \
5762 DUK_HOBJECT_A_SET_VALUE((heap), (h), (i), (v)) /* alias for above */
5763#define DUK_HOBJECT_H_SET_INDEX(heap,h,i,v) do { \
5764 DUK_HOBJECT_H_GET_INDEX((heap), (h), (i)) = (v); \
5765 } while (0)
5766
5767#define DUK_HOBJECT_E_SET_FLAG_BITS(heap,h,i,mask) do { \
5768 DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)] |= (mask); \
5769 } while (0)
5770
5771#define DUK_HOBJECT_E_CLEAR_FLAG_BITS(heap,h,i,mask) do { \
5772 DUK_HOBJECT_E_GET_FLAGS_BASE((heap), (h))[(i)] &= ~(mask); \
5773 } while (0)
5774
5775#define DUK_HOBJECT_E_SLOT_IS_WRITABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_WRITABLE) != 0)
5776#define DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_ENUMERABLE) != 0)
5777#define DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_CONFIGURABLE) != 0)
5778#define DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap,h,i) ((DUK_HOBJECT_E_GET_FLAGS((heap), (h), (i)) & DUK_PROPDESC_FLAG_ACCESSOR) != 0)
5779
5780#define DUK_HOBJECT_E_SLOT_SET_WRITABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_WRITABLE)
5781#define DUK_HOBJECT_E_SLOT_SET_ENUMERABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ENUMERABLE)
5782#define DUK_HOBJECT_E_SLOT_SET_CONFIGURABLE(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_CONFIGURABLE)
5783#define DUK_HOBJECT_E_SLOT_SET_ACCESSOR(heap,h,i) DUK_HOBJECT_E_SET_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ACCESSOR)
5784
5785#define DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_WRITABLE)
5786#define DUK_HOBJECT_E_SLOT_CLEAR_ENUMERABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ENUMERABLE)
5787#define DUK_HOBJECT_E_SLOT_CLEAR_CONFIGURABLE(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_CONFIGURABLE)
5788#define DUK_HOBJECT_E_SLOT_CLEAR_ACCESSOR(heap,h,i) DUK_HOBJECT_E_CLEAR_FLAG_BITS((heap), (h), (i),DUK_PROPDESC_FLAG_ACCESSOR)
5789
5790#define DUK_PROPDESC_IS_WRITABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_WRITABLE) != 0)
5791#define DUK_PROPDESC_IS_ENUMERABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_ENUMERABLE) != 0)
5792#define DUK_PROPDESC_IS_CONFIGURABLE(p) (((p)->flags & DUK_PROPDESC_FLAG_CONFIGURABLE) != 0)
5793#define DUK_PROPDESC_IS_ACCESSOR(p) (((p)->flags & DUK_PROPDESC_FLAG_ACCESSOR) != 0)
5794
5795#define DUK_HOBJECT_HASHIDX_UNUSED 0xffffffffUL
5796#define DUK_HOBJECT_HASHIDX_DELETED 0xfffffffeUL
5797
5798/*
5799 * Macros for accessing size fields
5800 */
5801
5802#if defined(DUK_USE_OBJSIZES16)
5803#define DUK_HOBJECT_GET_ESIZE(h) ((h)->e_size16)
5804#define DUK_HOBJECT_SET_ESIZE(h,v) do { (h)->e_size16 = (v); } while (0)
5805#define DUK_HOBJECT_GET_ENEXT(h) ((h)->e_next16)
5806#define DUK_HOBJECT_SET_ENEXT(h,v) do { (h)->e_next16 = (v); } while (0)
5807#define DUK_HOBJECT_POSTINC_ENEXT(h) ((h)->e_next16++)
5808#define DUK_HOBJECT_GET_ASIZE(h) ((h)->a_size16)
5809#define DUK_HOBJECT_SET_ASIZE(h,v) do { (h)->a_size16 = (v); } while (0)
5810#if defined(DUK_USE_HOBJECT_HASH_PART)
5811#define DUK_HOBJECT_GET_HSIZE(h) ((h)->h_size16)
5812#define DUK_HOBJECT_SET_HSIZE(h,v) do { (h)->h_size16 = (v); } while (0)
5813#else
5814#define DUK_HOBJECT_GET_HSIZE(h) 0
5815#define DUK_HOBJECT_SET_HSIZE(h,v) do { DUK_ASSERT((v) == 0); } while (0)
5816#endif
5817#else
5818#define DUK_HOBJECT_GET_ESIZE(h) ((h)->e_size)
5819#define DUK_HOBJECT_SET_ESIZE(h,v) do { (h)->e_size = (v); } while (0)
5820#define DUK_HOBJECT_GET_ENEXT(h) ((h)->e_next)
5821#define DUK_HOBJECT_SET_ENEXT(h,v) do { (h)->e_next = (v); } while (0)
5822#define DUK_HOBJECT_POSTINC_ENEXT(h) ((h)->e_next++)
5823#define DUK_HOBJECT_GET_ASIZE(h) ((h)->a_size)
5824#define DUK_HOBJECT_SET_ASIZE(h,v) do { (h)->a_size = (v); } while (0)
5825#if defined(DUK_USE_HOBJECT_HASH_PART)
5826#define DUK_HOBJECT_GET_HSIZE(h) ((h)->h_size)
5827#define DUK_HOBJECT_SET_HSIZE(h,v) do { (h)->h_size = (v); } while (0)
5828#else
5829#define DUK_HOBJECT_GET_HSIZE(h) 0
5830#define DUK_HOBJECT_SET_HSIZE(h,v) do { DUK_ASSERT((v) == 0); } while (0)
5831#endif
5832#endif
5833
5834/*
5835 * Misc
5836 */
5837
5838/* Maximum prototype traversal depth. Sanity limit which handles e.g.
5839 * prototype loops (even complex ones like 1->2->3->4->2->3->4->2->3->4).
5840 */
5841#define DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY 10000L
5842
5843/* Maximum traversal depth for "bound function" chains. */
5844#define DUK_HOBJECT_BOUND_CHAIN_SANITY 10000L
5845
5846/*
5847 * Ecmascript [[Class]]
5848 */
5849
5850/* range check not necessary because all 4-bit values are mapped */
5851#define DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(n) duk_class_number_to_stridx[(n)]
5852
5853#define DUK_HOBJECT_GET_CLASS_STRING(heap,h) \
5854 DUK_HEAP_GET_STRING( \
5855 (heap), \
5856 DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(DUK_HOBJECT_GET_CLASS_NUMBER((h))) \
5857 )
5858
5859/*
5860 * Macros for property handling
5861 */
5862
5863#if defined(DUK_USE_HEAPPTR16)
5864#define DUK_HOBJECT_GET_PROTOTYPE(heap,h) \
5865 ((duk_hobject *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->prototype16))
5866#define DUK_HOBJECT_SET_PROTOTYPE(heap,h,x) do { \
5867 (h)->prototype16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (x)); \
5868 } while (0)
5869#else
5870#define DUK_HOBJECT_GET_PROTOTYPE(heap,h) \
5871 ((h)->prototype)
5872#define DUK_HOBJECT_SET_PROTOTYPE(heap,h,x) do { \
5873 (h)->prototype = (x); \
5874 } while (0)
5875#endif
5876
5877/* note: this updates refcounts */
5878#define DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr,h,p) duk_hobject_set_prototype_updref((thr), (h), (p))
5879
5880/*
5881 * Resizing and hash behavior
5882 */
5883
5884/* Sanity limit on max number of properties (allocated, not necessarily used).
5885 * This is somewhat arbitrary, but if we're close to 2**32 properties some
5886 * algorithms will fail (e.g. hash size selection, next prime selection).
5887 * Also, we use negative array/entry table indices to indicate 'not found',
5888 * so anything above 0x80000000 will cause trouble now.
5889 */
5890#if defined(DUK_USE_OBJSIZES16)
5891#define DUK_HOBJECT_MAX_PROPERTIES 0x0000ffffUL
5892#else
5893#define DUK_HOBJECT_MAX_PROPERTIES 0x7fffffffUL /* 2**31-1 ~= 2G properties */
5894#endif
5895
5896/* higher value conserves memory; also note that linear scan is cache friendly */
5897#define DUK_HOBJECT_E_USE_HASH_LIMIT 32
5898
5899/* hash size relative to entries size: for value X, approx. hash_prime(e_size + e_size / X) */
5900#define DUK_HOBJECT_H_SIZE_DIVISOR 4 /* hash size approx. 1.25 times entries size */
5901
5902/* if new_size < L * old_size, resize without abandon check; L = 3-bit fixed point, e.g. 9 -> 9/8 = 112.5% */
5903#define DUK_HOBJECT_A_FAST_RESIZE_LIMIT 9 /* 112.5%, i.e. new size less than 12.5% higher -> fast resize */
5904
5905/* if density < L, abandon array part, L = 3-bit fixed point, e.g. 2 -> 2/8 = 25% */
5906/* limit is quite low: one array entry is 8 bytes, one normal entry is 4+1+8+4 = 17 bytes (with hash entry) */
5907#define DUK_HOBJECT_A_ABANDON_LIMIT 2 /* 25%, i.e. less than 25% used -> abandon */
5908
5909/* internal align target for props allocation, must be 2*n for some n */
5910#if (DUK_USE_ALIGN_BY == 4)
5911#define DUK_HOBJECT_ALIGN_TARGET 4
5912#elif (DUK_USE_ALIGN_BY == 8)
5913#define DUK_HOBJECT_ALIGN_TARGET 8
5914#elif (DUK_USE_ALIGN_BY == 1)
5915#define DUK_HOBJECT_ALIGN_TARGET 1
5916#else
5917#error invalid DUK_USE_ALIGN_BY
5918#endif
5919
5920/* controls for minimum entry part growth */
5921#define DUK_HOBJECT_E_MIN_GROW_ADD 16
5922#define DUK_HOBJECT_E_MIN_GROW_DIVISOR 8 /* 2^3 -> 1/8 = 12.5% min growth */
5923
5924/* controls for minimum array part growth */
5925#define DUK_HOBJECT_A_MIN_GROW_ADD 16
5926#define DUK_HOBJECT_A_MIN_GROW_DIVISOR 8 /* 2^3 -> 1/8 = 12.5% min growth */
5927
5928/* probe sequence */
5929#define DUK_HOBJECT_HASH_INITIAL(hash,h_size) ((hash) % (h_size))
5930#define DUK_HOBJECT_HASH_PROBE_STEP(hash) DUK_UTIL_GET_HASH_PROBE_STEP((hash))
5931
5932/*
5933 * PC-to-line constants
5934 */
5935
5936#define DUK_PC2LINE_SKIP 64
5937
5938/* maximum length for a SKIP-1 diffstream: 35 bits per entry, rounded up to bytes */
5939#define DUK_PC2LINE_MAX_DIFF_LENGTH (((DUK_PC2LINE_SKIP - 1) * 35 + 7) / 8)
5940
5941/*
5942 * Struct defs
5944
5945struct duk_propaccessor {
5946 duk_hobject *get;
5947 duk_hobject *set;
5949
5950union duk_propvalue {
5951 /* The get/set pointers could be 16-bit pointer compressed but it
5952 * would make no difference on 32-bit platforms because duk_tval is
5953 * 8 bytes or more anyway.
5954 */
5955 duk_tval v;
5958
5959struct duk_propdesc {
5960 /* read-only values 'lifted' for ease of use */
5961 duk_small_int_t flags;
5962 duk_hobject *get;
5963 duk_hobject *set;
5964
5965 /* for updating (all are set to < 0 for virtual properties) */
5966 duk_int_t e_idx; /* prop index in 'entry part', < 0 if not there */
5967 duk_int_t h_idx; /* prop index in 'hash part', < 0 if not there */
5968 duk_int_t a_idx; /* prop index in 'array part', < 0 if not there */
5970
5971struct duk_hobject {
5972 duk_heaphdr hdr;
5973
5974 /*
5975 * 'props' contains {key,value,flags} entries, optional array entries, and
5976 * an optional hash lookup table for non-array entries in a single 'sliced'
5977 * allocation. There are several layout options, which differ slightly in
5978 * generated code size/speed and alignment/padding; duk_features.h selects
5979 * the layout used.
5980 *
5981 * Layout 1 (DUK_USE_HOBJECT_LAYOUT_1):
5982 *
5983 * e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable)
5984 * e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable)
5985 * e_size * sizeof(duk_uint8_t) bytes of entry flags (e_next gc reachable)
5986 * a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable)
5987 * h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size),
5988 * 0xffffffffUL = unused, 0xfffffffeUL = deleted
5989 *
5990 * Layout 2 (DUK_USE_HOBJECT_LAYOUT_2):
5991 *
5992 * e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable)
5993 * e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable)
5994 * e_size * sizeof(duk_uint8_t) + pad bytes of entry flags (e_next gc reachable)
5995 * a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable)
5996 * h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size),
5997 * 0xffffffffUL = unused, 0xfffffffeUL = deleted
5998 *
5999 * Layout 3 (DUK_USE_HOBJECT_LAYOUT_3):
6000 *
6001 * e_size * sizeof(duk_propvalue) bytes of entry values (e_next gc reachable)
6002 * a_size * sizeof(duk_tval) bytes of (opt) array values (plain only) (all gc reachable)
6003 * e_size * sizeof(duk_hstring *) bytes of entry keys (e_next gc reachable)
6004 * h_size * sizeof(duk_uint32_t) bytes of (opt) hash indexes to entries (e_size),
6005 * 0xffffffffUL = unused, 0xfffffffeUL = deleted
6006 * e_size * sizeof(duk_uint8_t) bytes of entry flags (e_next gc reachable)
6007 *
6008 * In layout 1, the 'e_next' count is rounded to 4 or 8 on platforms
6009 * requiring 4 or 8 byte alignment. This ensures proper alignment
6010 * for the entries, at the cost of memory footprint. However, it's
6011 * probably preferable to use another layout on such platforms instead.
6012 *
6013 * In layout 2, the key and value parts are swapped to avoid padding
6014 * the key array on platforms requiring alignment by 8. The flags part
6015 * is padded to get alignment for array entries. The 'e_next' count does
6016 * not need to be rounded as in layout 1.
6017 *
6018 * In layout 3, entry values and array values are always aligned properly,
6019 * and assuming pointers are at most 8 bytes, so are the entry keys. Hash
6020 * indices will be properly aligned (assuming pointers are at least 4 bytes).
6021 * Finally, flags don't need additional alignment. This layout provides
6022 * compact allocations without padding (even on platforms with alignment
6023 * requirements) at the cost of a bit slower lookups.
6024 *
6025 * Objects with few keys don't have a hash index; keys are looked up linearly,
6026 * which is cache efficient because the keys are consecutive. Larger objects
6027 * have a hash index part which contains integer indexes to the entries part.
6028 *
6029 * A single allocation reduces memory allocation overhead but requires more
6030 * work when any part needs to be resized. A sliced allocation for entries
6031 * makes linear key matching faster on most platforms (more locality) and
6032 * skimps on flags size (which would be followed by 3 bytes of padding in
6033 * most architectures if entries were placed in a struct).
6034 *
6035 * 'props' also contains internal properties distinguished with a non-BMP
6036 * prefix. Often used properties should be placed early in 'props' whenever
6037 * possible to make accessing them as fast a possible.
6038 */
6039
6040#if defined(DUK_USE_HEAPPTR16)
6041 /* Located in duk_heaphdr h_extra16. Subclasses of duk_hobject (like
6042 * duk_hcompfunc) are not free to use h_extra16 for this reason.
6043 */
6044#else
6045 duk_uint8_t *props;
6046#endif
6047
6048 /* prototype: the only internal property lifted outside 'e' as it is so central */
6049#if defined(DUK_USE_HEAPPTR16)
6050 duk_uint16_t prototype16;
6051#else
6052 duk_hobject *prototype;
6053#endif
6054
6055#if defined(DUK_USE_OBJSIZES16)
6056 duk_uint16_t e_size16;
6057 duk_uint16_t e_next16;
6058 duk_uint16_t a_size16;
6059#if defined(DUK_USE_HOBJECT_HASH_PART)
6060 duk_uint16_t h_size16;
6061#endif
6062#else
6063 duk_uint32_t e_size; /* entry part size */
6064 duk_uint32_t e_next; /* index for next new key ([0,e_next[ are gc reachable) */
6065 duk_uint32_t a_size; /* array part size (entirely gc reachable) */
6066#if defined(DUK_USE_HOBJECT_HASH_PART)
6067 duk_uint32_t h_size; /* hash part size or 0 if unused */
6068#endif
6069#endif
6070};
6071
6072/*
6073 * Exposed data
6074 */
6075
6076#if !defined(DUK_SINGLE_FILE)
6077DUK_INTERNAL_DECL duk_uint8_t duk_class_number_to_stridx[32];
6078#endif /* !DUK_SINGLE_FILE */
6079
6080/*
6081 * Prototypes
6082 */
6083
6084/* alloc and init */
6085DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc(duk_heap *heap, duk_uint_t hobject_flags);
6086#if 0 /* unused */
6087DUK_INTERNAL_DECL duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, duk_uint_t hobject_flags);
6088#endif
6089DUK_INTERNAL_DECL duk_harray *duk_harray_alloc(duk_heap *heap, duk_uint_t hobject_flags);
6090DUK_INTERNAL_DECL duk_hcompfunc *duk_hcompfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags);
6091DUK_INTERNAL_DECL duk_hnatfunc *duk_hnatfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags);
6092#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
6093DUK_INTERNAL_DECL duk_hbufobj *duk_hbufobj_alloc(duk_heap *heap, duk_uint_t hobject_flags);
6094#endif
6095DUK_INTERNAL_DECL duk_hthread *duk_hthread_alloc(duk_heap *heap, duk_uint_t hobject_flags);
6096
6097/* resize */
6098DUK_INTERNAL_DECL void duk_hobject_realloc_props(duk_hthread *thr,
6099 duk_hobject *obj,
6100 duk_uint32_t new_e_size,
6101 duk_uint32_t new_a_size,
6102 duk_uint32_t new_h_size,
6103 duk_bool_t abandon_array);
6104
6105/* low-level property functions */
6106DUK_INTERNAL_DECL void duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *e_idx, duk_int_t *h_idx);
6107DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_hstring *key);
6108DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_entry_tval_ptr_and_attrs(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *out_attrs);
6109DUK_INTERNAL_DECL duk_tval *duk_hobject_find_existing_array_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_uarridx_t i);
6110DUK_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);
6111
6112/* XXX: when optimizing for guaranteed property slots, use a guaranteed
6113 * slot for internal value; this call can then access it directly.
6114 */
6115#define duk_hobject_get_internal_value_tval_ptr(heap,obj) \
6116 duk_hobject_find_existing_entry_tval_ptr((heap), (obj), DUK_HEAP_STRING_INT_VALUE((heap)))
6117
6118/* core property functions */
6119DUK_INTERNAL_DECL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key);
6120DUK_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);
6121DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_bool_t throw_flag);
6122DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key);
6123
6124/* internal property functions */
6125#define DUK_DELPROP_FLAG_THROW (1 << 0)
6126#define DUK_DELPROP_FLAG_FORCE (1 << 1)
6127DUK_INTERNAL_DECL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags);
6128DUK_INTERNAL_DECL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key);
6129DUK_INTERNAL_DECL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags);
6130DUK_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);
6131DUK_INTERNAL_DECL duk_size_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj);
6132
6133/* helpers for defineProperty() and defineProperties() */
6134DUK_INTERNAL_DECL
6135void duk_hobject_prepare_property_descriptor(duk_context *ctx,
6136 duk_idx_t idx_in,
6137 duk_uint_t *out_defprop_flags,
6138 duk_idx_t *out_idx_value,
6139 duk_hobject **out_getter,
6140 duk_hobject **out_setter);
6141DUK_INTERNAL_DECL
6142duk_bool_t duk_hobject_define_property_helper(duk_context *ctx,
6143 duk_uint_t defprop_flags,
6144 duk_hobject *obj,
6146 duk_idx_t idx_value,
6147 duk_hobject *get,
6148 duk_hobject *set,
6149 duk_bool_t throw_flag);
6150
6151/* Object built-in methods */
6152DUK_INTERNAL_DECL void duk_hobject_object_get_own_property_descriptor(duk_context *ctx, duk_idx_t obj_idx);
6153DUK_INTERNAL_DECL void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_freeze);
6154DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_is_sealed_frozen_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_frozen);
6155DUK_INTERNAL_DECL duk_bool_t duk_hobject_object_ownprop_helper(duk_context *ctx, duk_small_uint_t required_desc_flags);
6156
6157/* internal properties */
6158DUK_INTERNAL_DECL duk_bool_t duk_hobject_get_internal_value(duk_heap *heap, duk_hobject *obj, duk_tval *tv);
6159DUK_INTERNAL_DECL duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap, duk_hobject *obj);
6160
6161/* hobject management functions */
6162DUK_INTERNAL_DECL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj);
6163
6164/* ES2015 proxy */
6165#if defined(DUK_USE_ES6_PROXY)
6166DUK_INTERNAL_DECL duk_bool_t duk_hobject_proxy_check(duk_hthread *thr, duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler);
6167DUK_INTERNAL_DECL duk_hobject *duk_hobject_resolve_proxy_target(duk_hthread *thr, duk_hobject *obj);
6168#endif
6169
6170/* enumeration */
6171DUK_INTERNAL_DECL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint_t enum_flags);
6172DUK_INTERNAL_DECL duk_ret_t duk_hobject_get_enumerated_keys(duk_context *ctx, duk_small_uint_t enum_flags);
6173DUK_INTERNAL_DECL duk_bool_t duk_hobject_enumerator_next(duk_context *ctx, duk_bool_t get_value);
6174
6175/* macros */
6176DUK_INTERNAL_DECL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p);
6177
6178/* finalization */
6179#if defined(DUK_USE_FINALIZER_SUPPORT)
6180DUK_INTERNAL_DECL void duk_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj);
6181#endif
6182
6183/* pc2line */
6184#if defined(DUK_USE_PC2LINE)
6185DUK_INTERNAL_DECL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr *instrs, duk_uint_fast32_t length);
6186DUK_INTERNAL_DECL duk_uint_fast32_t duk_hobject_pc2line_query(duk_context *ctx, duk_idx_t idx_func, duk_uint_fast32_t pc);
6187#endif
6188
6189/* misc */
6190DUK_INTERNAL_DECL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr, duk_hobject *h, duk_hobject *p, duk_bool_t ignore_loop);
6191
6192#if !defined(DUK_USE_OBJECT_BUILTIN)
6193/* These declarations are needed when related built-in is disabled and
6194 * genbuiltins.py won't automatically emit the declerations.
6195 */
6196DUK_INTERNAL_DECL duk_ret_t duk_bi_object_prototype_to_string(duk_context *ctx);
6197DUK_INTERNAL_DECL duk_ret_t duk_bi_function_prototype(duk_context *ctx);
6198#endif
6199
6200#endif /* DUK_HOBJECT_H_INCLUDED */
6201/* #include duk_hcompfunc.h */
6202/*
6203 * Heap compiled function (Ecmascript function) representation.
6204 *
6205 * There is a single data buffer containing the Ecmascript function's
6206 * bytecode, constants, and inner functions.
6207 */
6208
6209#if !defined(DUK_HCOMPFUNC_H_INCLUDED)
6210#define DUK_HCOMPFUNC_H_INCLUDED
6211
6212/*
6213 * Field accessor macros
6214 */
6215
6216/* XXX: casts could be improved, especially for GET/SET DATA */
6217
6218#if defined(DUK_USE_HEAPPTR16)
6219#define DUK_HCOMPFUNC_GET_DATA(heap,h) \
6220 ((duk_hbuffer_fixed *) (void *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->data16))
6221#define DUK_HCOMPFUNC_SET_DATA(heap,h,v) do { \
6222 (h)->data16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
6223 } while (0)
6224#define DUK_HCOMPFUNC_GET_FUNCS(heap,h) \
6225 ((duk_hobject **) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->funcs16)))
6226#define DUK_HCOMPFUNC_SET_FUNCS(heap,h,v) do { \
6227 (h)->funcs16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
6228 } while (0)
6229#define DUK_HCOMPFUNC_GET_BYTECODE(heap,h) \
6230 ((duk_instr_t *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->bytecode16)))
6231#define DUK_HCOMPFUNC_SET_BYTECODE(heap,h,v) do { \
6232 (h)->bytecode16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
6233 } while (0)
6234#define DUK_HCOMPFUNC_GET_LEXENV(heap,h) \
6235 ((duk_hobject *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->lex_env16)))
6236#define DUK_HCOMPFUNC_SET_LEXENV(heap,h,v) do { \
6237 (h)->lex_env16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
6238 } while (0)
6239#define DUK_HCOMPFUNC_GET_VARENV(heap,h) \
6240 ((duk_hobject *) (void *) (DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (h)->var_env16)))
6241#define DUK_HCOMPFUNC_SET_VARENV(heap,h,v) do { \
6242 (h)->var_env16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
6243 } while (0)
6244#else
6245#define DUK_HCOMPFUNC_GET_DATA(heap,h) ((duk_hbuffer_fixed *) (void *) (h)->data)
6246#define DUK_HCOMPFUNC_SET_DATA(heap,h,v) do { \
6247 (h)->data = (duk_hbuffer *) (v); \
6248 } while (0)
6249#define DUK_HCOMPFUNC_GET_FUNCS(heap,h) ((h)->funcs)
6250#define DUK_HCOMPFUNC_SET_FUNCS(heap,h,v) do { \
6251 (h)->funcs = (v); \
6252 } while (0)
6253#define DUK_HCOMPFUNC_GET_BYTECODE(heap,h) ((h)->bytecode)
6254#define DUK_HCOMPFUNC_SET_BYTECODE(heap,h,v) do { \
6255 (h)->bytecode = (v); \
6256 } while (0)
6257#define DUK_HCOMPFUNC_GET_LEXENV(heap,h) ((h)->lex_env)
6258#define DUK_HCOMPFUNC_SET_LEXENV(heap,h,v) do { \
6259 (h)->lex_env = (v); \
6260 } while (0)
6261#define DUK_HCOMPFUNC_GET_VARENV(heap,h) ((h)->var_env)
6262#define DUK_HCOMPFUNC_SET_VARENV(heap,h,v) do { \
6263 (h)->var_env = (v); \
6264 } while (0)
6265#endif
6266
6267/*
6268 * Accessor macros for function specific data areas
6269 */
6270
6271/* Note: assumes 'data' is always a fixed buffer */
6272#define DUK_HCOMPFUNC_GET_BUFFER_BASE(heap,h) \
6273 DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPFUNC_GET_DATA((heap), (h)))
6274
6275#define DUK_HCOMPFUNC_GET_CONSTS_BASE(heap,h) \
6276 ((duk_tval *) (void *) DUK_HCOMPFUNC_GET_BUFFER_BASE((heap), (h)))
6277
6278#define DUK_HCOMPFUNC_GET_FUNCS_BASE(heap,h) \
6279 DUK_HCOMPFUNC_GET_FUNCS((heap), (h))
6280
6281#define DUK_HCOMPFUNC_GET_CODE_BASE(heap,h) \
6282 DUK_HCOMPFUNC_GET_BYTECODE((heap), (h))
6283
6284#define DUK_HCOMPFUNC_GET_CONSTS_END(heap,h) \
6285 ((duk_tval *) (void *) DUK_HCOMPFUNC_GET_FUNCS((heap), (h)))
6286
6287#define DUK_HCOMPFUNC_GET_FUNCS_END(heap,h) \
6288 ((duk_hobject **) (void *) DUK_HCOMPFUNC_GET_BYTECODE((heap), (h)))
6289
6290/* XXX: double evaluation of DUK_HCOMPFUNC_GET_DATA() */
6291#define DUK_HCOMPFUNC_GET_CODE_END(heap,h) \
6292 ((duk_instr_t *) (void *) (DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), DUK_HCOMPFUNC_GET_DATA((heap), (h))) + \
6293 DUK_HBUFFER_GET_SIZE((duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA((heap), h))))
6294
6295#define DUK_HCOMPFUNC_GET_CONSTS_SIZE(heap,h) \
6296 ( \
6297 (duk_size_t) \
6298 ( \
6299 ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CONSTS_END((heap), (h))) - \
6300 ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CONSTS_BASE((heap), (h))) \
6301 ) \
6302 )
6303
6304#define DUK_HCOMPFUNC_GET_FUNCS_SIZE(heap,h) \
6305 ( \
6306 (duk_size_t) \
6307 ( \
6308 ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_FUNCS_END((heap), (h))) - \
6309 ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_FUNCS_BASE((heap), (h))) \
6310 ) \
6311 )
6312
6313#define DUK_HCOMPFUNC_GET_CODE_SIZE(heap,h) \
6314 ( \
6315 (duk_size_t) \
6316 ( \
6317 ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CODE_END((heap),(h))) - \
6318 ((const duk_uint8_t *) DUK_HCOMPFUNC_GET_CODE_BASE((heap),(h))) \
6319 ) \
6320 )
6321
6322#define DUK_HCOMPFUNC_GET_CONSTS_COUNT(heap,h) \
6323 ((duk_size_t) (DUK_HCOMPFUNC_GET_CONSTS_SIZE((heap), (h)) / sizeof(duk_tval)))
6324
6325#define DUK_HCOMPFUNC_GET_FUNCS_COUNT(heap,h) \
6326 ((duk_size_t) (DUK_HCOMPFUNC_GET_FUNCS_SIZE((heap), (h)) / sizeof(duk_hobject *)))
6327
6328#define DUK_HCOMPFUNC_GET_CODE_COUNT(heap,h) \
6329 ((duk_size_t) (DUK_HCOMPFUNC_GET_CODE_SIZE((heap), (h)) / sizeof(duk_instr_t)))
6330
6331
6332/*
6333 * Main struct
6335
6336struct duk_hcompfunc {
6337 /* shared object part */
6338 duk_hobject obj;
6339
6340 /*
6341 * Pointers to function data area for faster access. Function
6342 * data is a buffer shared between all closures of the same
6343 * "template" function. The data buffer is always fixed (non-
6344 * dynamic, hence stable), with a layout as follows:
6345 *
6346 * constants (duk_tval)
6347 * inner functions (duk_hobject *)
6348 * bytecode (duk_instr_t)
6349 *
6350 * Note: bytecode end address can be computed from 'data' buffer
6351 * size. It is not strictly necessary functionally, assuming
6352 * bytecode never jumps outside its allocated area. However,
6353 * it's a safety/robustness feature for avoiding the chance of
6354 * executing random data as bytecode due to a compiler error.
6355 *
6356 * Note: values in the data buffer must be incref'd (they will
6357 * be decref'd on release) for every compiledfunction referring
6358 * to the 'data' element.
6359 */
6360
6361 /* Data area, fixed allocation, stable data ptrs. */
6362#if defined(DUK_USE_HEAPPTR16)
6363 duk_uint16_t data16;
6364#else
6365 duk_hbuffer *data;
6366#endif
6367
6368 /* No need for constants pointer (= same as data).
6369 *
6370 * When using 16-bit packing alignment to 4 is nice. 'funcs' will be
6371 * 4-byte aligned because 'constants' are duk_tvals. For now the
6372 * inner function pointers are not compressed, so that 'bytecode' will
6373 * also be 4-byte aligned.
6374 */
6375#if defined(DUK_USE_HEAPPTR16)
6376 duk_uint16_t funcs16;
6377 duk_uint16_t bytecode16;
6378#else
6379 duk_hobject **funcs;
6380 duk_instr_t *bytecode;
6381#endif
6382
6383 /* Lexenv: lexical environment of closure, NULL for templates.
6384 * Varenv: variable environment of closure, NULL for templates.
6385 */
6386#if defined(DUK_USE_HEAPPTR16)
6387 duk_uint16_t lex_env16;
6388 duk_uint16_t var_env16;
6389#else
6390 duk_hobject *lex_env;
6391 duk_hobject *var_env;
6392#endif
6393
6394 /*
6395 * 'nregs' registers are allocated on function entry, at most 'nargs'
6396 * are initialized to arguments, and the rest to undefined. Arguments
6397 * above 'nregs' are not mapped to registers. All registers in the
6398 * active stack range must be initialized because they are GC reachable.
6399 * 'nargs' is needed so that if the function is given more than 'nargs'
6400 * arguments, the additional arguments do not 'clobber' registers
6401 * beyond 'nregs' which must be consistently initialized to undefined.
6402 *
6403 * Usually there is no need to know which registers are mapped to
6404 * local variables. Registers may be allocated to variable in any
6405 * way (even including gaps). However, a register-variable mapping
6406 * must be the same for the duration of the function execution and
6407 * the register cannot be used for anything else.
6408 *
6409 * When looking up variables by name, the '_Varmap' map is used.
6410 * When an activation closes, registers mapped to arguments are
6411 * copied into the environment record based on the same map. The
6412 * reverse map (from register to variable) is not currently needed
6413 * at run time, except for debugging, so it is not maintained.
6414 */
6415
6416 duk_uint16_t nregs; /* regs to allocate */
6417 duk_uint16_t nargs; /* number of arguments allocated to regs */
6418
6419 /*
6420 * Additional control information is placed into the object itself
6421 * as internal properties to avoid unnecessary fields for the
6422 * majority of functions. The compiler tries to omit internal
6423 * control fields when possible.
6424 *
6425 * Function templates:
6426 *
6427 * {
6428 * name: "func", // declaration, named function expressions
6429 * fileName: <debug info for creating nice errors>
6430 * _Varmap: { "arg1": 0, "arg2": 1, "varname": 2 },
6431 * _Formals: [ "arg1", "arg2" ],
6432 * _Source: "function func(arg1, arg2) { ... }",
6433 * _Pc2line: <debug info for pc-to-line mapping>,
6434 * }
6435 *
6436 * Function instances:
6437 *
6438 * {
6439 * length: 2,
6440 * prototype: { constructor: <func> },
6441 * caller: <thrower>,
6442 * arguments: <thrower>,
6443 * name: "func", // declaration, named function expressions
6444 * fileName: <debug info for creating nice errors>
6445 * _Varmap: { "arg1": 0, "arg2": 1, "varname": 2 },
6446 * _Formals: [ "arg1", "arg2" ],
6447 * _Source: "function func(arg1, arg2) { ... }",
6448 * _Pc2line: <debug info for pc-to-line mapping>,
6449 * }
6450 *
6451 * More detailed description of these properties can be found
6452 * in the documentation.
6453 */
6454
6455#if defined(DUK_USE_DEBUGGER_SUPPORT)
6456 /* Line number range for function. Needed during debugging to
6457 * determine active breakpoints.
6458 */
6459 duk_uint32_t start_line;
6460 duk_uint32_t end_line;
6461#endif
6462};
6463
6464#endif /* DUK_HCOMPFUNC_H_INCLUDED */
6465/* #include duk_hnatfunc.h */
6466/*
6467 * Heap native function representation.
6468 */
6469
6470#if !defined(DUK_HNATFUNC_H_INCLUDED)
6471#define DUK_HNATFUNC_H_INCLUDED
6472
6473#define DUK_HNATFUNC_NARGS_VARARGS ((duk_int16_t) -1)
6474#define DUK_HNATFUNC_NARGS_MAX ((duk_int16_t) 0x7fff)
6475
6476struct duk_hnatfunc {
6477 /* shared object part */
6478 duk_hobject obj;
6479
6480 duk_c_function func;
6481 duk_int16_t nargs;
6482 duk_int16_t magic;
6483
6484 /* The 'magic' field allows an opaque 16-bit field to be accessed by the
6485 * Duktape/C function. This allows, for instance, the same native function
6486 * to be used for a set of very similar functions, with the 'magic' field
6487 * providing the necessary non-argument flags / values to guide the behavior
6488 * of the native function. The value is signed on purpose: it is easier to
6489 * convert a signed value to unsigned (simply AND with 0xffff) than vice
6490 * versa.
6491 *
6492 * Note: cannot place nargs/magic into the heaphdr flags, because
6493 * duk_hobject takes almost all flags already (and needs the spare).
6494 */
6495};
6496
6497#endif /* DUK_HNATFUNC_H_INCLUDED */
6498/* #include duk_hbufobj.h */
6499/*
6500 * Heap Buffer object representation. Used for all Buffer variants.
6501 */
6502
6503#if !defined(DUK_HBUFOBJ_H_INCLUDED)
6504#define DUK_HBUFOBJ_H_INCLUDED
6505
6506#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
6507
6508/* All element accessors are host endian now (driven by TypedArray spec). */
6509#define DUK_HBUFOBJ_ELEM_UINT8 0
6510#define DUK_HBUFOBJ_ELEM_UINT8CLAMPED 1
6511#define DUK_HBUFOBJ_ELEM_INT8 2
6512#define DUK_HBUFOBJ_ELEM_UINT16 3
6513#define DUK_HBUFOBJ_ELEM_INT16 4
6514#define DUK_HBUFOBJ_ELEM_UINT32 5
6515#define DUK_HBUFOBJ_ELEM_INT32 6
6516#define DUK_HBUFOBJ_ELEM_FLOAT32 7
6517#define DUK_HBUFOBJ_ELEM_FLOAT64 8
6518#define DUK_HBUFOBJ_ELEM_MAX 8
6519
6520#define DUK_ASSERT_HBUFOBJ_VALID(h) do { \
6521 DUK_ASSERT((h) != NULL); \
6522 DUK_ASSERT((h)->shift <= 3); \
6523 DUK_ASSERT((h)->elem_type <= DUK_HBUFOBJ_ELEM_MAX); \
6524 DUK_ASSERT(((h)->shift == 0 && (h)->elem_type == DUK_HBUFOBJ_ELEM_UINT8) || \
6525 ((h)->shift == 0 && (h)->elem_type == DUK_HBUFOBJ_ELEM_UINT8CLAMPED) || \
6526 ((h)->shift == 0 && (h)->elem_type == DUK_HBUFOBJ_ELEM_INT8) || \
6527 ((h)->shift == 1 && (h)->elem_type == DUK_HBUFOBJ_ELEM_UINT16) || \
6528 ((h)->shift == 1 && (h)->elem_type == DUK_HBUFOBJ_ELEM_INT16) || \
6529 ((h)->shift == 2 && (h)->elem_type == DUK_HBUFOBJ_ELEM_UINT32) || \
6530 ((h)->shift == 2 && (h)->elem_type == DUK_HBUFOBJ_ELEM_INT32) || \
6531 ((h)->shift == 2 && (h)->elem_type == DUK_HBUFOBJ_ELEM_FLOAT32) || \
6532 ((h)->shift == 3 && (h)->elem_type == DUK_HBUFOBJ_ELEM_FLOAT64)); \
6533 DUK_ASSERT((h)->is_typedarray == 0 || (h)->is_typedarray == 1); \
6534 DUK_ASSERT(DUK_HOBJECT_IS_BUFOBJ((duk_hobject *) (h))); \
6535 if ((h)->buf == NULL) { \
6536 DUK_ASSERT((h)->offset == 0); \
6537 DUK_ASSERT((h)->length == 0); \
6538 } else { \
6539 /* No assertions for offset or length; in particular, \
6540 * it's OK for length to be longer than underlying \
6541 * buffer. Just ensure they don't wrap when added. \
6542 */ \
6543 DUK_ASSERT((h)->offset + (h)->length >= (h)->offset); \
6544 } \
6545 } while (0)
6546
6547/* Get the current data pointer (caller must ensure buf != NULL) as a
6548 * duk_uint8_t ptr.
6549 */
6550#define DUK_HBUFOBJ_GET_SLICE_BASE(heap,h) \
6551 (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
6552 (((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR((heap), (h)->buf)) + (h)->offset))
6553
6554/* True if slice is full, i.e. offset is zero and length covers the entire
6555 * buffer. This status may change independently of the duk_hbufobj if
6556 * the underlying buffer is dynamic and changes without the hbufobj
6557 * being changed.
6558 */
6559#define DUK_HBUFOBJ_FULL_SLICE(h) \
6560 (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
6561 ((h)->offset == 0 && (h)->length == DUK_HBUFFER_GET_SIZE((h)->buf)))
6562
6563/* Validate that the whole slice [0,length[ is contained in the underlying
6564 * buffer. Caller must ensure 'buf' != NULL.
6565 */
6566#define DUK_HBUFOBJ_VALID_SLICE(h) \
6567 (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
6568 ((h)->offset + (h)->length <= DUK_HBUFFER_GET_SIZE((h)->buf)))
6569
6570/* Validate byte read/write for virtual 'offset', i.e. check that the
6571 * offset, taking into account h->offset, is within the underlying
6572 * buffer size. This is a safety check which is needed to ensure
6573 * that even a misconfigured duk_hbufobj never causes memory unsafe
6574 * behavior (e.g. if an underlying dynamic buffer changes after being
6575 * setup). Caller must ensure 'buf' != NULL.
6576 */
6577#define DUK_HBUFOBJ_VALID_BYTEOFFSET_INCL(h,off) \
6578 (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
6579 ((h)->offset + (off) < DUK_HBUFFER_GET_SIZE((h)->buf)))
6580
6581#define DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h,off) \
6582 (DUK_ASSERT_EXPR((h) != NULL), DUK_ASSERT_EXPR((h)->buf != NULL), \
6583 ((h)->offset + (off) <= DUK_HBUFFER_GET_SIZE((h)->buf)))
6584
6585/* Clamp an input byte length (already assumed to be within the nominal
6586 * duk_hbufobj 'length') to the current dynamic buffer limits to yield
6587 * a byte length limit that's safe for memory accesses. This value can
6588 * be invalidated by any side effect because it may trigger a user
6589 * callback that resizes the underlying buffer.
6590 */
6591#define DUK_HBUFOBJ_CLAMP_BYTELENGTH(h,len) \
6592 (DUK_ASSERT_EXPR((h) != NULL), \
6593 duk_hbufobj_clamp_bytelength((h), (len)))
6594
6595/* Typed arrays have virtual indices, ArrayBuffer and DataView do not. */
6596#define DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h) ((h)->is_typedarray)
6597
6598struct duk_hbufobj {
6599 /* Shared object part. */
6600 duk_hobject obj;
6601
6602 /* Underlying buffer (refcounted), may be NULL. */
6603 duk_hbuffer *buf;
6604
6605 /* .buffer reference to an ArrayBuffer, may be NULL. */
6606 duk_hobject *buf_prop;
6607
6608 /* Slice and accessor information.
6609 *
6610 * Because the underlying buffer may be dynamic, these may be
6611 * invalidated by the buffer being modified so that both offset
6612 * and length should be validated before every access. Behavior
6613 * when the underlying buffer has changed doesn't need to be clean:
6614 * virtual 'length' doesn't need to be affected, reads can return
6615 * zero/NaN, and writes can be ignored.
6616 *
6617 * Note that a data pointer cannot be precomputed because 'buf' may
6618 * be dynamic and its pointer unstable.
6619 */
6620
6621 duk_uint_t offset; /* byte offset to buf */
6622 duk_uint_t length; /* byte index limit for element access, exclusive */
6623 duk_uint8_t shift; /* element size shift:
6624 * 0 = u8/i8
6625 * 1 = u16/i16
6626 * 2 = u32/i32/float
6627 * 3 = double
6628 */
6629 duk_uint8_t elem_type; /* element type */
6630 duk_uint8_t is_typedarray;
6631};
6632
6633DUK_INTERNAL_DECL duk_uint_t duk_hbufobj_clamp_bytelength(duk_hbufobj *h_bufobj, duk_uint_t len);
6634DUK_INTERNAL_DECL void duk_hbufobj_push_uint8array_from_plain(duk_hthread *thr, duk_hbuffer *h_buf);
6635DUK_INTERNAL_DECL void duk_hbufobj_push_validated_read(duk_context *ctx, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size);
6636DUK_INTERNAL_DECL void duk_hbufobj_validated_write(duk_context *ctx, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size);
6637DUK_INTERNAL_DECL void duk_hbufobj_promote_plain(duk_context *ctx, duk_idx_t idx);
6638
6639#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
6640#endif /* DUK_HBUFOBJ_H_INCLUDED */
6641/* #include duk_hthread.h */
6642/*
6643 * Heap thread object representation.
6644 *
6645 * duk_hthread is also the 'context' (duk_context) for exposed APIs
6646 * which mostly operate on the topmost frame of the value stack.
6647 */
6648
6649#if !defined(DUK_HTHREAD_H_INCLUDED)
6650#define DUK_HTHREAD_H_INCLUDED
6651
6652/*
6653 * Stack constants
6654 */
6655
6656#define DUK_VALSTACK_GROW_STEP 128 /* roughly 1 kiB */
6657#define DUK_VALSTACK_SHRINK_THRESHOLD 256 /* roughly 2 kiB */
6658#define DUK_VALSTACK_SHRINK_SPARE 64 /* roughly 0.5 kiB */
6659#define DUK_VALSTACK_INITIAL_SIZE 128 /* roughly 1.0 kiB -> but rounds up to DUK_VALSTACK_GROW_STEP in practice */
6660#define DUK_VALSTACK_INTERNAL_EXTRA 64 /* internal extra elements assumed on function entry,
6661 * always added to user-defined 'extra' for e.g. the
6662 * duk_check_stack() call.
6663 */
6664#define DUK_VALSTACK_API_ENTRY_MINIMUM DUK_API_ENTRY_STACK
6665 /* number of elements guaranteed to be user accessible
6666 * (in addition to call arguments) on Duktape/C function entry.
6667 */
6668
6669/* Note: DUK_VALSTACK_INITIAL_SIZE must be >= DUK_VALSTACK_API_ENTRY_MINIMUM
6670 * + DUK_VALSTACK_INTERNAL_EXTRA so that the initial stack conforms to spare
6671 * requirements.
6672 */
6673
6674#define DUK_VALSTACK_DEFAULT_MAX 1000000L
6675
6676#define DUK_CALLSTACK_GROW_STEP 8 /* roughly 256 bytes */
6677#define DUK_CALLSTACK_SHRINK_THRESHOLD 16 /* roughly 512 bytes */
6678#define DUK_CALLSTACK_SHRINK_SPARE 8 /* roughly 256 bytes */
6679#define DUK_CALLSTACK_INITIAL_SIZE 8
6680#define DUK_CALLSTACK_DEFAULT_MAX 10000L
6681
6682#define DUK_CATCHSTACK_GROW_STEP 4 /* roughly 64 bytes */
6683#define DUK_CATCHSTACK_SHRINK_THRESHOLD 8 /* roughly 128 bytes */
6684#define DUK_CATCHSTACK_SHRINK_SPARE 4 /* roughly 64 bytes */
6685#define DUK_CATCHSTACK_INITIAL_SIZE 4
6686#define DUK_CATCHSTACK_DEFAULT_MAX 10000L
6687
6688/*
6689 * Activation defines
6690 */
6691
6692#define DUK_ACT_FLAG_STRICT (1 << 0) /* function executes in strict mode */
6693#define DUK_ACT_FLAG_TAILCALLED (1 << 1) /* activation has tail called one or more times */
6694#define DUK_ACT_FLAG_CONSTRUCT (1 << 2) /* function executes as a constructor (called via "new") */
6695#define DUK_ACT_FLAG_PREVENT_YIELD (1 << 3) /* activation prevents yield (native call or "new") */
6696#define DUK_ACT_FLAG_DIRECT_EVAL (1 << 4) /* activation is a direct eval call */
6697#define DUK_ACT_FLAG_BREAKPOINT_ACTIVE (1 << 5) /* activation has active breakpoint(s) */
6698
6699#define DUK_ACT_GET_FUNC(act) ((act)->func)
6700
6701/*
6702 * Flags for __FILE__ / __LINE__ registered into tracedata
6703 */
6704
6705#define DUK_TB_FLAG_NOBLAME_FILELINE (1 << 0) /* don't report __FILE__ / __LINE__ as fileName/lineNumber */
6706
6707/*
6708 * Catcher defines
6709 */
6710
6711/* flags field: LLLLLLFT, L = label (24 bits), F = flags (4 bits), T = type (4 bits) */
6712#define DUK_CAT_TYPE_MASK 0x0000000fUL
6713#define DUK_CAT_TYPE_BITS 4
6714#define DUK_CAT_LABEL_MASK 0xffffff00UL
6715#define DUK_CAT_LABEL_BITS 24
6716#define DUK_CAT_LABEL_SHIFT 8
6717
6718#define DUK_CAT_FLAG_CATCH_ENABLED (1 << 4) /* catch part will catch */
6719#define DUK_CAT_FLAG_FINALLY_ENABLED (1 << 5) /* finally part will catch */
6720#define DUK_CAT_FLAG_CATCH_BINDING_ENABLED (1 << 6) /* request to create catch binding */
6721#define DUK_CAT_FLAG_LEXENV_ACTIVE (1 << 7) /* catch or with binding is currently active */
6722
6723#define DUK_CAT_TYPE_UNKNOWN 0
6724#define DUK_CAT_TYPE_TCF 1
6725#define DUK_CAT_TYPE_LABEL 2
6726
6727#define DUK_CAT_GET_TYPE(c) ((c)->flags & DUK_CAT_TYPE_MASK)
6728#define DUK_CAT_GET_LABEL(c) (((c)->flags & DUK_CAT_LABEL_MASK) >> DUK_CAT_LABEL_SHIFT)
6729
6730#define DUK_CAT_HAS_CATCH_ENABLED(c) ((c)->flags & DUK_CAT_FLAG_CATCH_ENABLED)
6731#define DUK_CAT_HAS_FINALLY_ENABLED(c) ((c)->flags & DUK_CAT_FLAG_FINALLY_ENABLED)
6732#define DUK_CAT_HAS_CATCH_BINDING_ENABLED(c) ((c)->flags & DUK_CAT_FLAG_CATCH_BINDING_ENABLED)
6733#define DUK_CAT_HAS_LEXENV_ACTIVE(c) ((c)->flags & DUK_CAT_FLAG_LEXENV_ACTIVE)
6734
6735#define DUK_CAT_SET_CATCH_ENABLED(c) do { \
6736 (c)->flags |= DUK_CAT_FLAG_CATCH_ENABLED; \
6737 } while (0)
6738#define DUK_CAT_SET_FINALLY_ENABLED(c) do { \
6739 (c)->flags |= DUK_CAT_FLAG_FINALLY_ENABLED; \
6740 } while (0)
6741#define DUK_CAT_SET_CATCH_BINDING_ENABLED(c) do { \
6742 (c)->flags |= DUK_CAT_FLAG_CATCH_BINDING_ENABLED; \
6743 } while (0)
6744#define DUK_CAT_SET_LEXENV_ACTIVE(c) do { \
6745 (c)->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE; \
6746 } while (0)
6747
6748#define DUK_CAT_CLEAR_CATCH_ENABLED(c) do { \
6749 (c)->flags &= ~DUK_CAT_FLAG_CATCH_ENABLED; \
6750 } while (0)
6751#define DUK_CAT_CLEAR_FINALLY_ENABLED(c) do { \
6752 (c)->flags &= ~DUK_CAT_FLAG_FINALLY_ENABLED; \
6753 } while (0)
6754#define DUK_CAT_CLEAR_CATCH_BINDING_ENABLED(c) do { \
6755 (c)->flags &= ~DUK_CAT_FLAG_CATCH_BINDING_ENABLED; \
6756 } while (0)
6757#define DUK_CAT_CLEAR_LEXENV_ACTIVE(c) do { \
6758 (c)->flags &= ~DUK_CAT_FLAG_LEXENV_ACTIVE; \
6759 } while (0)
6760
6761/*
6762 * Thread defines
6763 */
6764
6765#if defined(DUK_USE_ROM_STRINGS)
6766#define DUK_HTHREAD_GET_STRING(thr,idx) \
6767 ((duk_hstring *) DUK_LOSE_CONST(duk_rom_strings_stridx[(idx)]))
6768#else /* DUK_USE_ROM_STRINGS */
6769#if defined(DUK_USE_HEAPPTR16)
6770#define DUK_HTHREAD_GET_STRING(thr,idx) \
6771 ((duk_hstring *) DUK_USE_HEAPPTR_DEC16((thr)->heap->heap_udata, (thr)->strs16[(idx)]))
6772#else
6773#define DUK_HTHREAD_GET_STRING(thr,idx) \
6774 ((thr)->strs[(idx)])
6775#endif
6776#endif /* DUK_USE_ROM_STRINGS */
6777
6778#define DUK_HTHREAD_GET_CURRENT_ACTIVATION(thr) (&(thr)->callstack[(thr)->callstack_top - 1])
6779
6780/* values for the state field */
6781#define DUK_HTHREAD_STATE_INACTIVE 1 /* thread not currently running */
6782#define DUK_HTHREAD_STATE_RUNNING 2 /* thread currently running (only one at a time) */
6783#define DUK_HTHREAD_STATE_RESUMED 3 /* thread resumed another thread (active but not running) */
6784#define DUK_HTHREAD_STATE_YIELDED 4 /* thread has yielded */
6785#define DUK_HTHREAD_STATE_TERMINATED 5 /* thread has terminated */
6786
6787/* Executor interrupt default interval when nothing else requires a
6788 * smaller value. The default interval must be small enough to allow
6789 * for reasonable execution timeout checking but large enough to keep
6790 * impact on execution performance low.
6791 */
6792#if defined(DUK_USE_INTERRUPT_COUNTER)
6793#define DUK_HTHREAD_INTCTR_DEFAULT (256L * 1024L)
6794#endif
6795
6796/*
6797 * Assert context is valid: non-NULL pointer, fields look sane.
6798 *
6799 * This is used by public API call entrypoints to catch invalid 'ctx' pointers
6800 * as early as possible; invalid 'ctx' pointers cause very odd and difficult to
6801 * diagnose behavior so it's worth checking even when the check is not 100%.
6802 */
6803
6804#if defined(DUK_USE_PREFER_SIZE)
6805#define DUK_ASSERT_CTX_VSSIZE(ctx) /*nop*/
6806#else
6807#define DUK_ASSERT_CTX_VSSIZE(ctx) \
6808 DUK_ASSERT((duk_size_t) (((duk_hthread *) (ctx))->valstack_end - ((duk_hthread *) (ctx))->valstack) == \
6809 ((duk_hthread *) (ctx))->valstack_size)
6810#endif
6811#define DUK_ASSERT_CTX_VALID(ctx) do { \
6812 DUK_ASSERT((ctx) != NULL); \
6813 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) (ctx)) == DUK_HTYPE_OBJECT); \
6814 DUK_ASSERT(DUK_HOBJECT_IS_THREAD((duk_hobject *) (ctx))); \
6815 DUK_ASSERT(((duk_hthread *) (ctx))->unused1 == 0); \
6816 DUK_ASSERT(((duk_hthread *) (ctx))->unused2 == 0); \
6817 DUK_ASSERT(((duk_hthread *) (ctx))->valstack != NULL); \
6818 DUK_ASSERT(((duk_hthread *) (ctx))->valstack_end >= ((duk_hthread *) (ctx))->valstack); \
6819 DUK_ASSERT(((duk_hthread *) (ctx))->valstack_top >= ((duk_hthread *) (ctx))->valstack); \
6820 DUK_ASSERT(((duk_hthread *) (ctx))->valstack_top >= ((duk_hthread *) (ctx))->valstack_bottom); \
6821 DUK_ASSERT(((duk_hthread *) (ctx))->valstack_end >= ((duk_hthread *) (ctx))->valstack_top); \
6822 DUK_ASSERT_CTX_VSSIZE((ctx)); \
6823 } while (0)
6824
6825/*
6826 * Assertion helpers.
6827 */
6828
6829#define DUK_ASSERT_STRIDX_VALID(val) \
6830 DUK_ASSERT((duk_uint_t) (val) < DUK_HEAP_NUM_STRINGS)
6831
6832#define DUK_ASSERT_BIDX_VALID(val) \
6833 DUK_ASSERT((duk_uint_t) (val) < DUK_NUM_BUILTINS)
6834
6835/*
6836 * Misc
6837 */
6838
6839/* Fast access to 'this' binding. Assumes there's a call in progress. */
6840#define DUK_HTHREAD_THIS_PTR(thr) \
6841 (DUK_ASSERT_EXPR((thr) != NULL), \
6842 DUK_ASSERT_EXPR((thr)->valstack_bottom > (thr)->valstack), \
6843 (thr)->valstack_bottom - 1)
6844
6845/*
6846 * Struct defines
6847 */
6848
6849/* XXX: for a memory-code tradeoff, remove 'func' and make it's access either a function
6850 * or a macro. This would make the activation 32 bytes long on 32-bit platforms again.
6851 */
6852
6853/* Note: it's nice if size is 2^N (at least for 32-bit platforms). */
6854struct duk_activation {
6855 duk_tval tv_func; /* borrowed: full duk_tval for function being executed; for lightfuncs */
6856 duk_hobject *func; /* borrowed: function being executed; for bound function calls, this is the final, real function, NULL for lightfuncs */
6857 duk_hobject *var_env; /* current variable environment (may be NULL if delayed) */
6858 duk_hobject *lex_env; /* current lexical environment (may be NULL if delayed) */
6859#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
6860 /* Previous value of 'func' caller, restored when unwound. Only in use
6861 * when 'func' is non-strict.
6862 */
6863 duk_hobject *prev_caller;
6864#endif
6865
6866 duk_instr_t *curr_pc; /* next instruction to execute (points to 'func' bytecode, stable pointer), NULL for native calls */
6867#if defined(DUK_USE_DEBUGGER_SUPPORT)
6868 duk_uint32_t prev_line; /* needed for stepping */
6869#endif
6870 duk_small_uint_t flags;
6871
6872 /* idx_bottom and idx_retval are only used for book-keeping of
6873 * Ecmascript-initiated calls, to allow returning to an Ecmascript
6874 * function properly. They are duk_size_t to match the convention
6875 * that value stack sizes are duk_size_t and local frame indices
6876 * are duk_idx_t.
6877 */
6878
6879 /* Bottom of valstack for this activation, used to reset
6880 * valstack_bottom on return; index is absolute. Note:
6881 * idx_top not needed because top is set to 'nregs' always
6882 * when returning to an Ecmascript activation.
6883 */
6884 duk_size_t idx_bottom;
6885
6886 /* Return value when returning to this activation (points to caller
6887 * reg, not callee reg); index is absolute (only set if activation is
6888 * not topmost).
6889 *
6890 * Note: idx_bottom is always set, while idx_retval is only applicable
6891 * for activations below the topmost one. Currently idx_retval for
6892 * the topmost activation is considered garbage (and it not initialized
6893 * on entry or cleared on return; may contain previous or garbage
6894 * values).
6895 */
6896 duk_size_t idx_retval;
6897
6898 /* Current 'this' binding is the value just below idx_bottom.
6899 * Previously, 'this' binding was handled with an index to the
6900 * (calling) valstack. This works for everything except tail
6901 * calls, which must not "cumulate" valstack temps.
6902 */
6903};
6904
6905/* Note: it's nice if size is 2^N (not 4x4 = 16 bytes on 32 bit) */
6906struct duk_catcher {
6907 duk_hstring *h_varname; /* borrowed reference to catch variable name (or NULL if none) */
6908 /* (reference is valid as long activation exists) */
6909 duk_instr_t *pc_base; /* resume execution from pc_base or pc_base+1 (points to 'func' bytecode, stable pointer) */
6910 duk_size_t callstack_index; /* callstack index of related activation */
6911 duk_size_t idx_base; /* idx_base and idx_base+1 get completion value and type */
6912 duk_uint32_t flags; /* type and control flags, label number */
6913};
6914
6915struct duk_hthread {
6916 /* Shared object part */
6917 duk_hobject obj;
6918
6919 /* Pointer to bytecode executor's 'curr_pc' variable. Used to copy
6920 * the current PC back into the topmost activation when activation
6921 * state is about to change (or "syncing" is otherwise needed). This
6922 * is rather awkward but important for performance, see execution.rst.
6923 */
6924 duk_instr_t **ptr_curr_pc;
6925
6926 /* Backpointers. */
6927 duk_heap *heap;
6928
6929 /* Current strictness flag: affects API calls. */
6930 duk_uint8_t strict;
6931
6932 /* Thread state. */
6933 duk_uint8_t state;
6934 duk_uint8_t unused1;
6935 duk_uint8_t unused2;
6936
6937 /* Sanity limits for stack sizes. */
6938 duk_size_t valstack_max;
6939 duk_size_t callstack_max;
6940 duk_size_t catchstack_max;
6941
6942 /* XXX: Valstack, callstack, and catchstack are currently assumed
6943 * to have non-NULL pointers. Relaxing this would not lead to big
6944 * benefits (except perhaps for terminated threads).
6945 */
6946
6947 /* Value stack: these are expressed as pointers for faster stack manipulation.
6948 * [valstack,valstack_top[ is GC-reachable, [valstack_top,valstack_end[ is
6949 * not GC-reachable but kept initialized as 'undefined'.
6950 */
6951 duk_tval *valstack; /* start of valstack allocation */
6952 duk_tval *valstack_end; /* end of valstack allocation (exclusive) */
6953 duk_tval *valstack_bottom; /* bottom of current frame */
6954 duk_tval *valstack_top; /* top of current frame (exclusive) */
6955#if !defined(DUK_USE_PREFER_SIZE)
6956 duk_size_t valstack_size; /* cached: valstack_end - valstack (in entries, not bytes) */
6957#endif
6958
6959 /* Call stack. [0,callstack_top[ is GC reachable. */
6960 duk_activation *callstack;
6961 duk_size_t callstack_size; /* allocation size */
6962 duk_size_t callstack_top; /* next to use, highest used is top - 1 */
6963 duk_size_t callstack_preventcount; /* number of activation records in callstack preventing a yield */
6964
6965 /* Catch stack. [0,catchstack_top[ is GC reachable. */
6966 duk_catcher *catchstack;
6967 duk_size_t catchstack_size; /* allocation size */
6968 duk_size_t catchstack_top; /* next to use, highest used is top - 1 */
6969
6970 /* Yield/resume book-keeping. */
6971 duk_hthread *resumer; /* who resumed us (if any) */
6972
6973 /* Current compiler state (if any), used for augmenting SyntaxErrors. */
6974 duk_compiler_ctx *compile_ctx;
6975
6976#if defined(DUK_USE_INTERRUPT_COUNTER)
6977 /* Interrupt counter for triggering a slow path check for execution
6978 * timeout, debugger interaction such as breakpoints, etc. The value
6979 * is valid for the current running thread, and both the init and
6980 * counter values are copied whenever a thread switch occurs. It's
6981 * important for the counter to be conveniently accessible for the
6982 * bytecode executor inner loop for performance reasons.
6983 */
6984 duk_int_t interrupt_counter; /* countdown state */
6985 duk_int_t interrupt_init; /* start value for current countdown */
6986#endif
6987
6988 /* Builtin-objects; may or may not be shared with other threads,
6989 * threads existing in different "compartments" will have different
6990 * built-ins. Must be stored on a per-thread basis because there
6991 * is no intermediate structure for a thread group / compartment.
6992 * This takes quite a lot of space, currently 43x4 = 172 bytes on
6993 * 32-bit platforms.
6994 *
6995 * In some cases the builtins array could be ROM based, but it's
6996 * sometimes edited (e.g. for sandboxing) so it's better to keep
6997 * this array in RAM.
6998 */
6999 duk_hobject *builtins[DUK_NUM_BUILTINS];
7000
7001 /* Convenience copies from heap/vm for faster access. */
7002#if defined(DUK_USE_ROM_STRINGS)
7003 /* No field needed when strings are in ROM. */
7004#else
7005#if defined(DUK_USE_HEAPPTR16)
7006 duk_uint16_t *strs16;
7007#else
7008 duk_hstring **strs;
7009#endif
7010#endif
7011};
7012
7013/*
7014 * Prototypes
7015 */
7016
7017DUK_INTERNAL_DECL void duk_hthread_copy_builtin_objects(duk_hthread *thr_from, duk_hthread *thr_to);
7018DUK_INTERNAL_DECL void duk_hthread_create_builtin_objects(duk_hthread *thr);
7019DUK_INTERNAL_DECL duk_bool_t duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr);
7020DUK_INTERNAL_DECL void duk_hthread_terminate(duk_hthread *thr);
7021
7022DUK_INTERNAL_DECL void duk_hthread_callstack_grow(duk_hthread *thr);
7023DUK_INTERNAL_DECL void duk_hthread_callstack_shrink_check(duk_hthread *thr);
7024DUK_INTERNAL_DECL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_top);
7025DUK_INTERNAL_DECL void duk_hthread_catchstack_grow(duk_hthread *thr);
7026DUK_INTERNAL_DECL void duk_hthread_catchstack_shrink_check(duk_hthread *thr);
7027DUK_INTERNAL_DECL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new_top);
7028
7029DUK_INTERNAL_DECL duk_activation *duk_hthread_get_current_activation(duk_hthread *thr);
7030DUK_INTERNAL_DECL void *duk_hthread_get_valstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */
7031DUK_INTERNAL_DECL void *duk_hthread_get_callstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */
7032DUK_INTERNAL_DECL void *duk_hthread_get_catchstack_ptr(duk_heap *heap, void *ud); /* indirect allocs */
7033
7034#if defined(DUK_USE_DEBUGGER_SUPPORT)
7035DUK_INTERNAL_DECL duk_uint_fast32_t duk_hthread_get_act_curr_pc(duk_hthread *thr, duk_activation *act);
7036#endif
7037DUK_INTERNAL_DECL duk_uint_fast32_t duk_hthread_get_act_prev_pc(duk_hthread *thr, duk_activation *act);
7038DUK_INTERNAL_DECL void duk_hthread_sync_currpc(duk_hthread *thr);
7039DUK_INTERNAL_DECL void duk_hthread_sync_and_null_currpc(duk_hthread *thr);
7040
7041#endif /* DUK_HTHREAD_H_INCLUDED */
7042/* #include duk_harray.h */
7043/*
7044 * Heap Array object representation. Used for actual Array instances.
7045 *
7046 * All objects with the exotic array behavior (which must coincide with having
7047 * internal class array) MUST be duk_harrays. No other object can be a
7048 * duk_harray. However, duk_harrays may not always have an array part.
7049 */
7050
7051#if !defined(DUK_HARRAY_H_INCLUDED)
7052#define DUK_HARRAY_H_INCLUDED
7053
7054#define DUK_ASSERT_HARRAY_VALID(h) do { \
7055 DUK_ASSERT((h) != NULL); \
7056 DUK_ASSERT(DUK_HOBJECT_IS_ARRAY((duk_hobject *) (h))); \
7057 DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY((duk_hobject *) (h))); \
7058 } while (0)
7059
7060#define DUK_HARRAY_LENGTH_WRITABLE(h) (!(h)->length_nonwritable)
7061#define DUK_HARRAY_LENGTH_NONWRITABLE(h) ((h)->length_nonwritable)
7062#define DUK_HARRAY_SET_LENGTH_WRITABLE(h) do { (h)->length_nonwritable = 0; } while (0)
7063#define DUK_HARRAY_SET_LENGTH_NONWRITABLE(h) do { (h)->length_nonwritable = 1; } while (0)
7064
7065struct duk_harray {
7066 /* Shared object part. */
7067 duk_hobject obj;
7068
7069 /* Array .length.
7070 *
7071 * At present Array .length may be smaller, equal, or even larger
7072 * than the allocated underlying array part. Fast path code must
7073 * always take this into account carefully.
7074 */
7075 duk_uint32_t length;
7076
7077 /* Array .length property attributes. The property is always
7078 * non-enumerable and non-configurable. It's initially writable
7079 * but per Object.defineProperty() rules it can be made non-writable
7080 * even if it is non-configurable. Thus we need to track the
7081 * writability explicitly.
7082 *
7083 * XXX: this field to be eliminated and moved into duk_hobject
7084 * flags field to save space.
7085 */
7086 duk_bool_t length_nonwritable;
7087};
7088
7089#endif /* DUK_HARRAY_H_INCLUDED */
7090/* #include duk_hbuffer.h */
7091/*
7092 * Heap buffer representation.
7093 *
7094 * Heap allocated user data buffer which is either:
7095 *
7096 * 1. A fixed size buffer (data follows header statically)
7097 * 2. A dynamic size buffer (data pointer follows header)
7098 *
7099 * The data pointer for a variable size buffer of zero size may be NULL.
7100 */
7101
7102#if !defined(DUK_HBUFFER_H_INCLUDED)
7103#define DUK_HBUFFER_H_INCLUDED
7104
7105/*
7106 * Flags
7107 *
7108 * Fixed buffer: 0
7109 * Dynamic buffer: DUK_HBUFFER_FLAG_DYNAMIC
7110 * External buffer: DUK_HBUFFER_FLAG_DYNAMIC | DUK_HBUFFER_FLAG_EXTERNAL
7111 */
7112
7113#define DUK_HBUFFER_FLAG_DYNAMIC DUK_HEAPHDR_USER_FLAG(0) /* buffer is behind a pointer, dynamic or external */
7114#define DUK_HBUFFER_FLAG_EXTERNAL DUK_HEAPHDR_USER_FLAG(1) /* buffer pointer is to an externally allocated buffer */
7115
7116#define DUK_HBUFFER_HAS_DYNAMIC(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC)
7117#define DUK_HBUFFER_HAS_EXTERNAL(x) DUK_HEAPHDR_CHECK_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL)
7118
7119#define DUK_HBUFFER_SET_DYNAMIC(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC)
7120#define DUK_HBUFFER_SET_EXTERNAL(x) DUK_HEAPHDR_SET_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL)
7121
7122#define DUK_HBUFFER_CLEAR_DYNAMIC(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_DYNAMIC)
7123#define DUK_HBUFFER_CLEAR_EXTERNAL(x) DUK_HEAPHDR_CLEAR_FLAG_BITS(&(x)->hdr, DUK_HBUFFER_FLAG_EXTERNAL)
7124
7125/*
7126 * Misc defines
7127 */
7128
7129/* Impose a maximum buffer length for now. Restricted artificially to
7130 * ensure resize computations or adding a heap header length won't
7131 * overflow size_t and that a signed duk_int_t can hold a buffer
7132 * length. The limit should be synchronized with DUK_HSTRING_MAX_BYTELEN.
7133 */
7134
7135#if defined(DUK_USE_BUFLEN16)
7136#define DUK_HBUFFER_MAX_BYTELEN (0x0000ffffUL)
7137#else
7138/* Intentionally not 0x7fffffffUL; at least JSON code expects that
7139 * 2*len + 2 fits in 32 bits.
7140 */
7141#define DUK_HBUFFER_MAX_BYTELEN (0x7ffffffeUL)
7142#endif
7143
7144/*
7145 * Field access
7146 */
7147
7148/* Get/set the current user visible size, without accounting for a dynamic
7149 * buffer's "spare" (= usable size).
7150 */
7151#if defined(DUK_USE_BUFLEN16)
7152/* size stored in duk_heaphdr unused flag bits */
7153#define DUK_HBUFFER_GET_SIZE(x) ((x)->hdr.h_flags >> 16)
7154#define DUK_HBUFFER_SET_SIZE(x,v) do { \
7155 duk_size_t duk__v; \
7156 duk__v = (v); \
7157 DUK_ASSERT(duk__v <= 0xffffUL); \
7158 (x)->hdr.h_flags = ((x)->hdr.h_flags & 0x0000ffffUL) | (((duk_uint32_t) duk__v) << 16); \
7159 } while (0)
7160#define DUK_HBUFFER_ADD_SIZE(x,dv) do { \
7161 (x)->hdr.h_flags += ((dv) << 16); \
7162 } while (0)
7163#define DUK_HBUFFER_SUB_SIZE(x,dv) do { \
7164 (x)->hdr.h_flags -= ((dv) << 16); \
7165 } while (0)
7166#else
7167#define DUK_HBUFFER_GET_SIZE(x) (((duk_hbuffer *) (x))->size)
7168#define DUK_HBUFFER_SET_SIZE(x,v) do { \
7169 ((duk_hbuffer *) (x))->size = (v); \
7170 } while (0)
7171#define DUK_HBUFFER_ADD_SIZE(x,dv) do { \
7172 (x)->size += (dv); \
7173 } while (0)
7174#define DUK_HBUFFER_SUB_SIZE(x,dv) do { \
7175 (x)->size -= (dv); \
7176 } while (0)
7177#endif
7178
7179#define DUK_HBUFFER_FIXED_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x))
7180#define DUK_HBUFFER_FIXED_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x))
7181
7182#define DUK_HBUFFER_DYNAMIC_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x))
7183#define DUK_HBUFFER_DYNAMIC_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x), (v))
7184#define DUK_HBUFFER_DYNAMIC_ADD_SIZE(x,dv) DUK_HBUFFER_ADD_SIZE((duk_hbuffer *) (x), (dv))
7185#define DUK_HBUFFER_DYNAMIC_SUB_SIZE(x,dv) DUK_HBUFFER_SUB_SIZE((duk_hbuffer *) (x), (dv))
7186
7187#define DUK_HBUFFER_EXTERNAL_GET_SIZE(x) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) (x))
7188#define DUK_HBUFFER_EXTERNAL_SET_SIZE(x,v) DUK_HBUFFER_SET_SIZE((duk_hbuffer *) (x), (v))
7189
7190#define DUK_HBUFFER_FIXED_GET_DATA_PTR(heap,x) ((duk_uint8_t *) (((duk_hbuffer_fixed *) (x)) + 1))
7191
7192#if defined(DUK_USE_HEAPPTR16)
7193#define DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap,x) \
7194 ((void *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, ((duk_heaphdr *) (x))->h_extra16))
7195#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap,x,v) do { \
7196 ((duk_heaphdr *) (x))->h_extra16 = DUK_USE_HEAPPTR_ENC16((heap)->heap_udata, (void *) (v)); \
7197 } while (0)
7198#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(heap,x) do { \
7199 ((duk_heaphdr *) (x))->h_extra16 = 0; /* assume 0 <=> NULL */ \
7200 } while (0)
7201#else
7202#define DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap,x) ((x)->curr_alloc)
7203#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap,x,v) do { \
7204 (x)->curr_alloc = (void *) (v); \
7205 } while (0)
7206#define DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(heap,x) do { \
7207 (x)->curr_alloc = (void *) NULL; \
7208 } while (0)
7209#endif
7210
7211/* No pointer compression because pointer is potentially outside of
7212 * Duktape heap.
7213 */
7214#if defined(DUK_USE_HEAPPTR16)
7215#define DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap,x) \
7216 ((void *) (x)->curr_alloc)
7217#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap,x,v) do { \
7218 (x)->curr_alloc = (void *) (v); \
7219 } while (0)
7220#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR_NULL(heap,x) do { \
7221 (x)->curr_alloc = (void *) NULL; \
7222 } while (0)
7223#else
7224#define DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap,x) \
7225 ((void *) (x)->curr_alloc)
7226#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap,x,v) do { \
7227 (x)->curr_alloc = (void *) (v); \
7228 } while (0)
7229#define DUK_HBUFFER_EXTERNAL_SET_DATA_PTR_NULL(heap,x) do { \
7230 (x)->curr_alloc = (void *) NULL; \
7231 } while (0)
7232#endif
7233
7234/* Get a pointer to the current buffer contents (matching current allocation
7235 * size). May be NULL for zero size dynamic/external buffer.
7236 */
7237#if defined(DUK_USE_HEAPPTR16)
7238#define DUK_HBUFFER_GET_DATA_PTR(heap,x) ( \
7239 DUK_HBUFFER_HAS_DYNAMIC((x)) ? \
7240 ( \
7241 DUK_HBUFFER_HAS_EXTERNAL((x)) ? \
7242 DUK_HBUFFER_EXTERNAL_GET_DATA_PTR((heap), (duk_hbuffer_external *) (x)) : \
7243 DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((heap), (duk_hbuffer_dynamic *) (x)) \
7244 ) : \
7245 DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (x)) \
7246 )
7247#else
7248/* Without heap pointer compression duk_hbuffer_dynamic and duk_hbuffer_external
7249 * have the same layout so checking for fixed vs. dynamic (or external) is enough.
7250 */
7251#define DUK_HBUFFER_GET_DATA_PTR(heap,x) ( \
7252 DUK_HBUFFER_HAS_DYNAMIC((x)) ? \
7253 DUK_HBUFFER_DYNAMIC_GET_DATA_PTR((heap), (duk_hbuffer_dynamic *) (x)) : \
7254 DUK_HBUFFER_FIXED_GET_DATA_PTR((heap), (duk_hbuffer_fixed *) (x)) \
7256#endif
7257
7258/*
7259 * Structs
7260 */
7261
7262/* Shared prefix for all buffer types. */
7263struct duk_hbuffer {
7264 duk_heaphdr hdr;
7265
7266 /* It's not strictly necessary to track the current size, but
7267 * it is useful for writing robust native code.
7268 */
7269
7270 /* Current size (not counting a dynamic buffer's "spare"). */
7271#if defined(DUK_USE_BUFLEN16)
7272 /* Stored in duk_heaphdr unused flags. */
7273#else
7274 duk_size_t size;
7275#endif
7276
7277 /*
7278 * Data following the header depends on the DUK_HBUFFER_FLAG_DYNAMIC
7279 * flag.
7280 *
7281 * If the flag is clear (the buffer is a fixed size one), the buffer
7282 * data follows the header directly, consisting of 'size' bytes.
7283 *
7284 * If the flag is set, the actual buffer is allocated separately, and
7285 * a few control fields follow the header. Specifically:
7286 *
7287 * - a "void *" pointing to the current allocation
7288 * - a duk_size_t indicating the full allocated size (always >= 'size')
7289 *
7290 * If DUK_HBUFFER_FLAG_EXTERNAL is set, the buffer has been allocated
7291 * by user code, so that Duktape won't be able to resize it and won't
7292 * free it. This allows buffers to point to e.g. an externally
7293 * allocated structure such as a frame buffer.
7294 *
7295 * Unlike strings, no terminator byte (NUL) is guaranteed after the
7296 * data. This would be convenient, but would pad aligned user buffers
7297 * unnecessarily upwards in size. For instance, if user code requested
7298 * a 64-byte dynamic buffer, 65 bytes would actually be allocated which
7299 * would then potentially round upwards to perhaps 68 or 72 bytes.
7300 */
7302
7303/* Fixed buffer; data follows struct, with proper alignment guaranteed by
7304 * struct size.
7305 */
7306#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA)
7307#pragma pack(push, 8)
7308#endif
7309struct duk_hbuffer_fixed {
7310 /* A union is used here as a portable struct size / alignment trick:
7311 * by adding a 32-bit or a 64-bit (unused) union member, the size of
7312 * the struct is effectively forced to be a multiple of 4 or 8 bytes
7313 * (respectively) without increasing the size of the struct unless
7314 * necessary.
7315 */
7316 union {
7317 struct {
7318 duk_heaphdr hdr;
7319#if defined(DUK_USE_BUFLEN16)
7320 /* Stored in duk_heaphdr unused flags. */
7321#else
7322 duk_size_t size;
7323#endif
7324 } s;
7325#if (DUK_USE_ALIGN_BY == 4)
7326 duk_uint32_t dummy_for_align4;
7327#elif (DUK_USE_ALIGN_BY == 8)
7328 duk_double_t dummy_for_align8;
7329#elif (DUK_USE_ALIGN_BY == 1)
7330 /* no extra padding */
7331#else
7332#error invalid DUK_USE_ALIGN_BY
7333#endif
7334 } u;
7335
7336 /*
7337 * Data follows the struct header. The struct size is padded by the
7338 * compiler based on the struct members. This guarantees that the
7339 * buffer data will be aligned-by-4 but not necessarily aligned-by-8.
7340 *
7341 * On platforms where alignment does not matter, the struct padding
7342 * could be removed (if there is any). On platforms where alignment
7343 * by 8 is required, the struct size must be forced to be a multiple
7344 * of 8 by some means. Without it, some user code may break, and also
7345 * Duktape itself breaks (e.g. the compiler stores duk_tvals in a
7346 * dynamic buffer).
7347 */
7348}
7349#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_GCC_ATTR)
7350__attribute__ ((aligned (8)))
7351#elif (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_CLANG_ATTR)
7352__attribute__ ((aligned (8)))
7353#endif
7354;
7355#if (DUK_USE_ALIGN_BY == 8) && defined(DUK_USE_PACK_MSVC_PRAGMA)
7356#pragma pack(pop)
7357#endif
7358
7359/* Dynamic buffer with 'curr_alloc' pointing to a dynamic area allocated using
7360 * heap allocation primitives. Also used for external buffers when low memory
7361 * options are not used.
7362 */
7363struct duk_hbuffer_dynamic {
7364 duk_heaphdr hdr;
7365
7366#if defined(DUK_USE_BUFLEN16)
7367 /* Stored in duk_heaphdr unused flags. */
7368#else
7369 duk_size_t size;
7370#endif
7371
7372#if defined(DUK_USE_HEAPPTR16)
7373 /* Stored in duk_heaphdr h_extra16. */
7374#else
7375 void *curr_alloc; /* may be NULL if alloc_size == 0 */
7376#endif
7377
7378 /*
7379 * Allocation size for 'curr_alloc' is alloc_size. There is no
7380 * automatic NUL terminator for buffers (see above for rationale).
7381 *
7382 * 'curr_alloc' is explicitly allocated with heap allocation
7383 * primitives and will thus always have alignment suitable for
7384 * e.g. duk_tval and an IEEE double.
7385 */
7386};
7387
7388/* External buffer with 'curr_alloc' managed by user code and pointing to an
7389 * arbitrary address. When heap pointer compression is not used, this struct
7390 * has the same layout as duk_hbuffer_dynamic.
7391 */
7392struct duk_hbuffer_external {
7393 duk_heaphdr hdr;
7394
7395#if defined(DUK_USE_BUFLEN16)
7396 /* Stored in duk_heaphdr unused flags. */
7397#else
7398 duk_size_t size;
7399#endif
7400
7401 /* Cannot be compressed as a heap pointer because may point to
7402 * an arbitrary address.
7403 */
7404 void *curr_alloc; /* may be NULL if alloc_size == 0 */
7405};
7406
7407/*
7408 * Prototypes
7409 */
7410
7411DUK_INTERNAL_DECL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk_small_uint_t flags, void **out_bufdata);
7412DUK_INTERNAL_DECL void *duk_hbuffer_get_dynalloc_ptr(duk_heap *heap, void *ud); /* indirect allocs */
7413
7414/* dynamic buffer ops */
7415DUK_INTERNAL_DECL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_size_t new_size);
7416DUK_INTERNAL_DECL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *buf);
7417
7418#endif /* DUK_HBUFFER_H_INCLUDED */
7419/* #include duk_heap.h */
7420/*
7421 * Heap structure.
7422 *
7423 * Heap contains allocated heap objects, interned strings, and built-in
7424 * strings for one or more threads.
7425 */
7426
7427#if !defined(DUK_HEAP_H_INCLUDED)
7428#define DUK_HEAP_H_INCLUDED
7429
7430/* alloc function typedefs in duktape.h */
7431
7432/*
7433 * Heap flags
7434 */
7435
7436#define DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING (1 << 0) /* mark-and-sweep is currently running */
7437#define DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED (1 << 1) /* mark-and-sweep marking reached a recursion limit and must use multi-pass marking */
7438#define DUK_HEAP_FLAG_REFZERO_FREE_RUNNING (1 << 2) /* refcount code is processing refzero list */
7439#define DUK_HEAP_FLAG_ERRHANDLER_RUNNING (1 << 3) /* an error handler (user callback to augment/replace error) is running */
7440#define DUK_HEAP_FLAG_INTERRUPT_RUNNING (1 << 4) /* executor interrupt running (used to avoid nested interrupts) */
7441#define DUK_HEAP_FLAG_FINALIZER_NORESCUE (1 << 5) /* heap destruction ongoing, finalizer rescue no longer possible */
7442#define DUK_HEAP_FLAG_DEBUGGER_PAUSED (1 << 6) /* debugger is paused: talk with debug client until step/resume */
7443
7444#define DUK__HEAP_HAS_FLAGS(heap,bits) ((heap)->flags & (bits))
7445#define DUK__HEAP_SET_FLAGS(heap,bits) do { \
7446 (heap)->flags |= (bits); \
7447 } while (0)
7448#define DUK__HEAP_CLEAR_FLAGS(heap,bits) do { \
7449 (heap)->flags &= ~(bits); \
7450 } while (0)
7451
7452#define DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING)
7453#define DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
7454#define DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING)
7455#define DUK_HEAP_HAS_ERRHANDLER_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING)
7456#define DUK_HEAP_HAS_INTERRUPT_RUNNING(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
7457#define DUK_HEAP_HAS_FINALIZER_NORESCUE(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
7458#define DUK_HEAP_HAS_DEBUGGER_PAUSED(heap) DUK__HEAP_HAS_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED)
7459
7460#define DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING)
7461#define DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
7462#define DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING)
7463#define DUK_HEAP_SET_ERRHANDLER_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING)
7464#define DUK_HEAP_SET_INTERRUPT_RUNNING(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
7465#define DUK_HEAP_SET_FINALIZER_NORESCUE(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
7466#define DUK_HEAP_SET_DEBUGGER_PAUSED(heap) DUK__HEAP_SET_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED)
7467
7468#define DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RUNNING)
7469#define DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_MARKANDSWEEP_RECLIMIT_REACHED)
7470#define DUK_HEAP_CLEAR_REFZERO_FREE_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_REFZERO_FREE_RUNNING)
7471#define DUK_HEAP_CLEAR_ERRHANDLER_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_ERRHANDLER_RUNNING)
7472#define DUK_HEAP_CLEAR_INTERRUPT_RUNNING(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_INTERRUPT_RUNNING)
7473#define DUK_HEAP_CLEAR_FINALIZER_NORESCUE(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_FINALIZER_NORESCUE)
7474#define DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap) DUK__HEAP_CLEAR_FLAGS((heap), DUK_HEAP_FLAG_DEBUGGER_PAUSED)
7475
7476/*
7477 * Longjmp types, also double as identifying continuation type for a rethrow (in 'finally')
7478 */
7479
7480#define DUK_LJ_TYPE_UNKNOWN 0 /* unused */
7481#define DUK_LJ_TYPE_THROW 1 /* value1 -> error object */
7482#define DUK_LJ_TYPE_YIELD 2 /* value1 -> yield value, iserror -> error / normal */
7483#define DUK_LJ_TYPE_RESUME 3 /* value1 -> resume value, value2 -> resumee thread, iserror -> error/normal */
7484#define DUK_LJ_TYPE_BREAK 4 /* value1 -> label number, pseudo-type to indicate a break continuation (for ENDFIN) */
7485#define DUK_LJ_TYPE_CONTINUE 5 /* value1 -> label number, pseudo-type to indicate a continue continuation (for ENDFIN) */
7486#define DUK_LJ_TYPE_RETURN 6 /* value1 -> return value, pseudo-type to indicate a return continuation (for ENDFIN) */
7487#define DUK_LJ_TYPE_NORMAL 7 /* no value, pseudo-type to indicate a normal continuation (for ENDFIN) */
7488
7489/*
7490 * Mark-and-sweep flags
7491 *
7492 * These are separate from heap level flags now but could be merged.
7493 * The heap structure only contains a 'base mark-and-sweep flags'
7494 * field and the GC caller can impose further flags.
7495 */
7496
7497#define DUK_MS_FLAG_EMERGENCY (1 << 0) /* emergency mode: try extra hard */
7498#define DUK_MS_FLAG_NO_STRINGTABLE_RESIZE (1 << 1) /* don't resize stringtable (but may sweep it); needed during stringtable resize */
7499#define DUK_MS_FLAG_NO_OBJECT_COMPACTION (1 << 2) /* don't compact objects; needed during object property allocation resize */
7500#define DUK_MS_FLAG_NO_FINALIZERS (1 << 3) /* don't run finalizers; leave finalizable objects in finalize_list for next round */
7501#define DUK_MS_FLAG_SKIP_FINALIZERS (1 << 4) /* don't run finalizers; queue finalizable objects back to heap_allocated */
7502
7503/*
7504 * Thread switching
7505 *
7506 * To switch heap->curr_thread, use the macro below so that interrupt counters
7507 * get updated correctly. The macro allows a NULL target thread because that
7508 * happens e.g. in call handling.
7509 */
7510
7511#if defined(DUK_USE_INTERRUPT_COUNTER)
7512#define DUK_HEAP_SWITCH_THREAD(heap,newthr) duk_heap_switch_thread((heap), (newthr))
7513#else
7514#define DUK_HEAP_SWITCH_THREAD(heap,newthr) do { \
7515 (heap)->curr_thread = (newthr); \
7516 } while (0)
7517#endif
7518
7519/*
7520 * Other heap related defines
7521 */
7522
7523/* Mark-and-sweep interval is relative to combined count of objects and
7524 * strings kept in the heap during the latest mark-and-sweep pass.
7525 * Fixed point .8 multiplier and .0 adder. Trigger count (interval) is
7526 * decreased by each (re)allocation attempt (regardless of size), and each
7527 * refzero processed object.
7528 *
7529 * 'SKIP' indicates how many (re)allocations to wait until a retry if
7530 * GC is skipped because there is no thread do it with yet (happens
7531 * only during init phases).
7532 */
7533#if defined(DUK_USE_REFERENCE_COUNTING)
7534#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT 12800L /* 50x heap size */
7535#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L
7536#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP 256L
7537#else
7538#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT 256L /* 1x heap size */
7539#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD 1024L
7540#define DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP 256L
7541#endif
7542
7543/* Stringcache is used for speeding up char-offset-to-byte-offset
7544 * translations for non-ASCII strings.
7545 */
7546#define DUK_HEAP_STRCACHE_SIZE 4
7547#define DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT 16 /* strings up to the this length are not cached */
7548
7549/* helper to insert a (non-string) heap object into heap allocated list */
7550#define DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap,hdr) duk_heap_insert_into_heap_allocated((heap),(hdr))
7551
7552/*
7553 * Stringtable
7554 */
7555
7556/* initial stringtable size, must be prime and higher than DUK_UTIL_MIN_HASH_PRIME */
7557#define DUK_STRTAB_INITIAL_SIZE 17
7558
7559/* indicates a deleted string; any fixed non-NULL, non-hstring pointer works */
7560#define DUK_STRTAB_DELETED_MARKER(heap) ((duk_hstring *) heap)
7561
7562/* resizing parameters */
7563#define DUK_STRTAB_MIN_FREE_DIVISOR 4 /* load factor max 75% */
7564#define DUK_STRTAB_MIN_USED_DIVISOR 4 /* load factor min 25% */
7565#define DUK_STRTAB_GROW_ST_SIZE(n) ((n) + (n)) /* used entries + approx 100% -> reset load to 50% */
7566
7567#define DUK_STRTAB_U32_MAX_STRLEN 10 /* 4'294'967'295 */
7568#define DUK_STRTAB_HIGHEST_32BIT_PRIME 0xfffffffbUL
7569
7570/* probe sequence (open addressing) */
7571#define DUK_STRTAB_HASH_INITIAL(hash,h_size) ((hash) % (h_size))
7572#define DUK_STRTAB_HASH_PROBE_STEP(hash) DUK_UTIL_GET_HASH_PROBE_STEP((hash))
7573
7574/* fixed top level hashtable size (separate chaining) */
7575#define DUK_STRTAB_CHAIN_SIZE DUK_USE_STRTAB_CHAIN_SIZE
7576
7577/*
7578 * Built-in strings
7579 */
7580
7581/* heap string indices are autogenerated in duk_strings.h */
7582#if defined(DUK_USE_ROM_STRINGS)
7583#define DUK_HEAP_GET_STRING(heap,idx) \
7584 ((duk_hstring *) DUK_LOSE_CONST(duk_rom_strings_stridx[(idx)]))
7585#else /* DUK_USE_ROM_STRINGS */
7586#if defined(DUK_USE_HEAPPTR16)
7587#define DUK_HEAP_GET_STRING(heap,idx) \
7588 ((duk_hstring *) DUK_USE_HEAPPTR_DEC16((heap)->heap_udata, (heap)->strs16[(idx)]))
7589#else
7590#define DUK_HEAP_GET_STRING(heap,idx) \
7591 ((heap)->strs[(idx)])
7592#endif
7593#endif /* DUK_USE_ROM_STRINGS */
7594
7595/*
7596 * Raw memory calls: relative to heap, but no GC interaction
7597 */
7598
7599#define DUK_ALLOC_RAW(heap,size) \
7600 ((heap)->alloc_func((heap)->heap_udata, (size)))
7601
7602#define DUK_REALLOC_RAW(heap,ptr,newsize) \
7603 ((heap)->realloc_func((heap)->heap_udata, (void *) (ptr), (newsize)))
7604
7605#define DUK_FREE_RAW(heap,ptr) \
7606 ((heap)->free_func((heap)->heap_udata, (void *) (ptr)))
7607
7608/*
7609 * Memory calls: relative to heap, GC interaction, but no error throwing.
7610 *
7611 * XXX: Currently a mark-and-sweep triggered by memory allocation will run
7612 * using the heap->heap_thread. This thread is also used for running
7613 * mark-and-sweep finalization; this is not ideal because it breaks the
7614 * isolation between multiple global environments.
7615 *
7616 * Notes:
7617 *
7618 * - DUK_FREE() is required to ignore NULL and any other possible return
7619 * value of a zero-sized alloc/realloc (same as ANSI C free()).
7620 *
7621 * - There is no DUK_REALLOC_ZEROED because we don't assume to know the
7622 * old size. Caller must zero the reallocated memory.
7623 *
7624 * - DUK_REALLOC_INDIRECT() must be used when a mark-and-sweep triggered
7625 * by an allocation failure might invalidate the original 'ptr', thus
7626 * causing a realloc retry to use an invalid pointer. Example: we're
7627 * reallocating the value stack and a finalizer resizes the same value
7628 * stack during mark-and-sweep. The indirect variant requests for the
7629 * current location of the pointer being reallocated using a callback
7630 * right before every realloc attempt; this circuitous approach is used
7631 * to avoid strict aliasing issues in a more straightforward indirect
7632 * pointer (void **) approach. Note: the pointer in the storage
7633 * location is read but is NOT updated; the caller must do that.
7634 */
7635
7636/* callback for indirect reallocs, request for current pointer */
7637typedef void *(*duk_mem_getptr)(duk_heap *heap, void *ud);
7638
7639#define DUK_ALLOC(heap,size) duk_heap_mem_alloc((heap), (size))
7640#define DUK_ALLOC_ZEROED(heap,size) duk_heap_mem_alloc_zeroed((heap), (size))
7641#define DUK_REALLOC(heap,ptr,newsize) duk_heap_mem_realloc((heap), (ptr), (newsize))
7642#define DUK_REALLOC_INDIRECT(heap,cb,ud,newsize) duk_heap_mem_realloc_indirect((heap), (cb), (ud), (newsize))
7643#define DUK_FREE(heap,ptr) duk_heap_mem_free((heap), (ptr))
7644
7645/*
7646 * Memory constants
7647 */
7648
7649#define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT 5 /* Retry allocation after mark-and-sweep for this
7650 * many times. A single mark-and-sweep round is
7651 * not guaranteed to free all unreferenced memory
7652 * because of finalization (in fact, ANY number of
7653 * rounds is strictly not enough).
7654 */
7655
7656#define DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT 3 /* Starting from this round, use emergency mode
7657 * for mark-and-sweep.
7658 */
7659
7660/*
7661 * Debugger support
7662 */
7663
7664/* Maximum number of breakpoints. Only breakpoints that are set are
7665 * consulted so increasing this has no performance impact.
7666 */
7667#define DUK_HEAP_MAX_BREAKPOINTS 16
7668
7669/* Opcode interval for a Date-based status/peek rate limit check. Only
7670 * relevant when debugger is attached. Requesting a timestamp may be a
7671 * slow operation on some platforms so this shouldn't be too low. On the
7672 * other hand a high value makes Duktape react to a pause request slowly.
7673 */
7674#define DUK_HEAP_DBG_RATELIMIT_OPCODES 4000
7675
7676/* Milliseconds between status notify and transport peeks. */
7677#define DUK_HEAP_DBG_RATELIMIT_MILLISECS 200
7678
7679/* Step types */
7680#define DUK_STEP_TYPE_NONE 0
7681#define DUK_STEP_TYPE_INTO 1
7682#define DUK_STEP_TYPE_OVER 2
7683#define DUK_STEP_TYPE_OUT 3
7684
7685struct duk_breakpoint {
7686 duk_hstring *filename;
7687 duk_uint32_t line;
7688};
7689
7690#if defined(DUK_USE_DEBUGGER_SUPPORT)
7691#define DUK_HEAP_IS_DEBUGGER_ATTACHED(heap) ((heap)->dbg_read_cb != NULL)
7692#define DUK_HEAP_CLEAR_STEP_STATE(heap) do { \
7693 (heap)->dbg_step_type = DUK_STEP_TYPE_NONE; \
7694 (heap)->dbg_step_thread = NULL; \
7695 (heap)->dbg_step_csindex = 0; \
7696 (heap)->dbg_step_startline = 0; \
7697 } while (0)
7698#define DUK_HEAP_SET_PAUSED(heap) do { \
7699 DUK_HEAP_SET_DEBUGGER_PAUSED(heap); \
7700 (heap)->dbg_state_dirty = 1; \
7701 DUK_HEAP_CLEAR_STEP_STATE((heap)); \
7702 } while (0)
7703#define DUK_HEAP_CLEAR_PAUSED(heap) do { \
7704 DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap); \
7705 (heap)->dbg_state_dirty = 1; \
7706 DUK_HEAP_CLEAR_STEP_STATE((heap)); \
7707 } while (0)
7708#define DUK_HEAP_IS_PAUSED(heap) (DUK_HEAP_HAS_DEBUGGER_PAUSED((heap)))
7709#endif /* DUK_USE_DEBUGGER_SUPPORT */
7710
7711/*
7712 * String cache should ideally be at duk_hthread level, but that would
7713 * cause string finalization to slow down relative to the number of
7714 * threads; string finalization must check the string cache for "weak"
7715 * references to the string being finalized to avoid dead pointers.
7717 * Thus, string caches are now at the heap level now.
7718 */
7719
7720struct duk_strcache {
7721 duk_hstring *h;
7722 duk_uint32_t bidx;
7723 duk_uint32_t cidx;
7724};
7725
7726/*
7727 * Longjmp state, contains the information needed to perform a longjmp.
7728 * Longjmp related values are written to value1, value2, and iserror.
7729 */
7730
7731struct duk_ljstate {
7732 duk_jmpbuf *jmpbuf_ptr; /* current setjmp() catchpoint */
7733 duk_small_uint_t type; /* longjmp type */
7734 duk_bool_t iserror; /* isError flag for yield */
7735 duk_tval value1; /* 1st related value (type specific) */
7736 duk_tval value2; /* 2nd related value (type specific) */
7737};
7738
7739/*
7740 * Stringtable entry for fixed size stringtable
7741 */
7742
7743struct duk_strtab_entry {
7744#if defined(DUK_USE_HEAPPTR16)
7745 /* A 16-bit listlen makes sense with 16-bit heap pointers: there
7746 * won't be space for 64k strings anyway.
7747 */
7748 duk_uint16_t listlen; /* if 0, 'str16' used, if > 0, 'strlist16' used */
7749 union {
7750 duk_uint16_t strlist16;
7751 duk_uint16_t str16;
7752 } u;
7753#else
7754 duk_size_t listlen; /* if 0, 'str' used, if > 0, 'strlist' used */
7755 union {
7756 duk_hstring **strlist;
7757 duk_hstring *str;
7758 } u;
7759#endif
7760};
7761
7762/*
7763 * Main heap structure
7764 */
7765
7766struct duk_heap {
7767 duk_small_uint_t flags;
7768
7769 /* Allocator functions. */
7770 duk_alloc_function alloc_func;
7771 duk_realloc_function realloc_func;
7772 duk_free_function free_func;
7773
7774 /* Heap udata, used for allocator functions but also for other heap
7775 * level callbacks like fatal function, pointer compression, etc.
7776 */
7777 void *heap_udata;
7778
7779 /* Precomputed pointers when using 16-bit heap pointer packing. */
7780#if defined(DUK_USE_HEAPPTR16)
7781 duk_uint16_t heapptr_null16;
7782 duk_uint16_t heapptr_deleted16;
7783#endif
7784
7785 /* Fatal error handling, called e.g. when a longjmp() is needed but
7786 * lj.jmpbuf_ptr is NULL. fatal_func must never return; it's not
7787 * declared as "noreturn" because doing that for typedefs is a bit
7788 * challenging portability-wise.
7789 */
7790 duk_fatal_function fatal_func;
7791
7792 /* allocated heap objects */
7793 duk_heaphdr *heap_allocated;
7794
7795 /* work list for objects whose refcounts are zero but which have not been
7796 * "finalized"; avoids recursive C calls when refcounts go to zero in a
7797 * chain of objects.
7798 */
7799#if defined(DUK_USE_REFERENCE_COUNTING)
7800 duk_heaphdr *refzero_list;
7801 duk_heaphdr *refzero_list_tail;
7802#endif
7803
7804 /* mark-and-sweep control */
7805#if defined(DUK_USE_VOLUNTARY_GC)
7806 duk_int_t mark_and_sweep_trigger_counter;
7807#endif
7808 duk_int_t mark_and_sweep_recursion_depth;
7809
7810 /* mark-and-sweep flags automatically active (used for critical sections) */
7811 duk_small_uint_t mark_and_sweep_base_flags;
7812
7813 /* work list for objects to be finalized (by mark-and-sweep) */
7814 duk_heaphdr *finalize_list;
7815
7816 /* longjmp state */
7817 duk_ljstate lj;
7818
7819 /* marker for detecting internal "double faults", see duk_error_throw.c */
7820 duk_bool_t handling_error;
7821
7822 /* heap thread, used internally and for finalization */
7823 duk_hthread *heap_thread;
7824
7825 /* current thread */
7826 duk_hthread *curr_thread; /* currently running thread */
7827
7828 /* heap level "stash" object (e.g., various reachability roots) */
7829 duk_hobject *heap_object;
7830
7831 /* duk_handle_call / duk_handle_safe_call recursion depth limiting */
7832 duk_int_t call_recursion_depth;
7833 duk_int_t call_recursion_limit;
7834
7835 /* mix-in value for computing string hashes; should be reasonably unpredictable */
7836 duk_uint32_t hash_seed;
7837
7838 /* rnd_state for duk_util_tinyrandom.c */
7839#if !defined(DUK_USE_GET_RANDOM_DOUBLE)
7840#if defined(DUK_USE_PREFER_SIZE) || !defined(DUK_USE_64BIT_OPS)
7841 duk_uint32_t rnd_state; /* State for Shamir's three-op algorithm */
7842#else
7843 duk_uint64_t rnd_state[2]; /* State for xoroshiro128+ */
7844#endif
7845#endif
7846
7847 /* counter for unique local symbol creation */
7848 /* XXX: When 64-bit types are available, it would be more efficient to
7849 * use a duk_uint64_t at least for incrementing but maybe also for
7850 * string formatting in the Symbol constructor.
7851 */
7852 duk_uint32_t sym_counter[2];
7853
7854 /* For manual debugging: instruction count based on executor and
7855 * interrupt counter book-keeping. Inspect debug logs to see how
7856 * they match up.
7857 */
7858#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
7859 duk_int_t inst_count_exec;
7860 duk_int_t inst_count_interrupt;
7861#endif
7862
7863 /* debugger */
7864
7865#if defined(DUK_USE_DEBUGGER_SUPPORT)
7866 /* callbacks and udata; dbg_read_cb != NULL is used to indicate attached state */
7867 duk_debug_read_function dbg_read_cb; /* required, NULL implies detached */
7868 duk_debug_write_function dbg_write_cb; /* required */
7869 duk_debug_peek_function dbg_peek_cb;
7870 duk_debug_read_flush_function dbg_read_flush_cb;
7871 duk_debug_write_flush_function dbg_write_flush_cb;
7872 duk_debug_request_function dbg_request_cb;
7873 duk_debug_detached_function dbg_detached_cb;
7874 void *dbg_udata;
7875
7876 /* debugger state, only relevant when attached */
7877 duk_bool_t dbg_processing; /* currently processing messages or breakpoints: don't enter message processing recursively (e.g. no breakpoints when processing debugger eval) */
7878 duk_bool_t dbg_state_dirty; /* resend state next time executor is about to run */
7879 duk_bool_t dbg_force_restart; /* force executor restart to recheck breakpoints; used to handle function returns (see GH-303) */
7880 duk_bool_t dbg_detaching; /* debugger detaching; used to avoid calling detach handler recursively */
7881 duk_small_uint_t dbg_step_type; /* step type: none, step into, step over, step out */
7882 duk_hthread *dbg_step_thread; /* borrowed; NULL if no step state (NULLed in unwind) */
7883 duk_size_t dbg_step_csindex; /* callstack index */
7884 duk_uint32_t dbg_step_startline; /* starting line number */
7885 duk_breakpoint dbg_breakpoints[DUK_HEAP_MAX_BREAKPOINTS]; /* breakpoints: [0,breakpoint_count[ gc reachable */
7886 duk_small_uint_t dbg_breakpoint_count;
7887 duk_breakpoint *dbg_breakpoints_active[DUK_HEAP_MAX_BREAKPOINTS + 1]; /* currently active breakpoints: NULL term, borrowed pointers */
7888 /* XXX: make active breakpoints actual copies instead of pointers? */
7889
7890 /* These are for rate limiting Status notifications and transport peeking. */
7891 duk_uint32_t dbg_exec_counter; /* cumulative opcode execution count (overflows are OK) */
7892 duk_uint32_t dbg_last_counter; /* value of dbg_exec_counter when we last did a Date-based check */
7893 duk_double_t dbg_last_time; /* time when status/peek was last done (Date-based rate limit) */
7894
7895 /* Used to support single-byte stream lookahead. */
7896 duk_bool_t dbg_have_next_byte;
7897 duk_uint8_t dbg_next_byte;
7898#endif
7899
7900 /* string intern table (weak refs) */
7901#if defined(DUK_USE_STRTAB_PROBE)
7902#if defined(DUK_USE_HEAPPTR16)
7903 duk_uint16_t *strtable16;
7904#else
7905 duk_hstring **strtable;
7906#endif
7907 duk_uint32_t st_size; /* alloc size in elements */
7908 duk_uint32_t st_used; /* used elements (includes DELETED) */
7909#endif
7910
7911 /* XXX: static alloc is OK until separate chaining stringtable
7912 * resizing is implemented.
7913 */
7914#if defined(DUK_USE_STRTAB_CHAIN)
7915 duk_strtab_entry strtable[DUK_STRTAB_CHAIN_SIZE];
7916#endif
7917
7918 /* string access cache (codepoint offset -> byte offset) for fast string
7919 * character looping; 'weak' reference which needs special handling in GC.
7920 */
7921 duk_strcache strcache[DUK_HEAP_STRCACHE_SIZE];
7922
7923 /* built-in strings */
7924#if defined(DUK_USE_ROM_STRINGS)
7925 /* No field needed when strings are in ROM. */
7926#else
7927#if defined(DUK_USE_HEAPPTR16)
7928 duk_uint16_t strs16[DUK_HEAP_NUM_STRINGS];
7929#else
7930 duk_hstring *strs[DUK_HEAP_NUM_STRINGS];
7931#endif
7932#endif
7933};
7934
7935/*
7936 * Prototypes
7937 */
7938
7939DUK_INTERNAL_DECL
7940duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
7941 duk_realloc_function realloc_func,
7942 duk_free_function free_func,
7943 void *heap_udata,
7944 duk_fatal_function fatal_func);
7945DUK_INTERNAL_DECL void duk_heap_free(duk_heap *heap);
7946DUK_INTERNAL_DECL void duk_free_hobject(duk_heap *heap, duk_hobject *h);
7947DUK_INTERNAL_DECL void duk_free_hbuffer(duk_heap *heap, duk_hbuffer *h);
7948DUK_INTERNAL_DECL void duk_free_hstring(duk_heap *heap, duk_hstring *h);
7949DUK_INTERNAL_DECL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr);
7950
7951DUK_INTERNAL_DECL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr);
7952#if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_REFERENCE_COUNTING)
7953DUK_INTERNAL_DECL void duk_heap_remove_any_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr);
7954#endif
7955#if defined(DUK_USE_INTERRUPT_COUNTER)
7956DUK_INTERNAL_DECL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr);
7957#endif
7958
7959#if 0 /*unused*/
7960DUK_INTERNAL_DECL duk_hstring *duk_heap_string_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen);
7961#endif
7962DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen);
7963DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t len);
7964#if 0 /*unused*/
7965DUK_INTERNAL_DECL duk_hstring *duk_heap_string_lookup_u32(duk_heap *heap, duk_uint32_t val);
7966#endif
7967DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_u32(duk_heap *heap, duk_uint32_t val);
7968DUK_INTERNAL_DECL duk_hstring *duk_heap_string_intern_u32_checked(duk_hthread *thr, duk_uint32_t val);
7969#if defined(DUK_USE_REFERENCE_COUNTING)
7970DUK_INTERNAL_DECL void duk_heap_string_remove(duk_heap *heap, duk_hstring *h);
7971#endif
7972#if defined(DUK_USE_MS_STRINGTABLE_RESIZE)
7973DUK_INTERNAL_DECL void duk_heap_force_strtab_resize(duk_heap *heap);
7974#endif
7975DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap);
7976#if defined(DUK_USE_DEBUG)
7977DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap);
7978#endif
7979
7980DUK_INTERNAL_DECL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h);
7981DUK_INTERNAL_DECL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset);
7982
7983#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS)
7984DUK_INTERNAL_DECL void *duk_default_alloc_function(void *udata, duk_size_t size);
7985DUK_INTERNAL_DECL void *duk_default_realloc_function(void *udata, void *ptr, duk_size_t newsize);
7986DUK_INTERNAL_DECL void duk_default_free_function(void *udata, void *ptr);
7987#endif
7988
7989DUK_INTERNAL_DECL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size);
7990DUK_INTERNAL_DECL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size);
7991DUK_INTERNAL_DECL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize);
7992DUK_INTERNAL_DECL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize);
7993DUK_INTERNAL_DECL void duk_heap_mem_free(duk_heap *heap, void *ptr);
7994
7995#if defined(DUK_USE_REFERENCE_COUNTING)
7996DUK_INTERNAL_DECL void duk_refzero_free_pending(duk_hthread *thr);
7997DUK_INTERNAL_DECL void duk_heaphdr_refcount_finalize(duk_hthread *thr, duk_heaphdr *hdr);
7998#if 0 /* Not needed: fast path handles inline; slow path uses duk_heaphdr_decref() which is needed anyway. */
7999DUK_INTERNAL_DECL void duk_hstring_decref(duk_hthread *thr, duk_hstring *h);
8000DUK_INTERNAL_DECL void duk_hstring_decref_norz(duk_hthread *thr, duk_hstring *h);
8001DUK_INTERNAL_DECL void duk_hbuffer_decref(duk_hthread *thr, duk_hbuffer *h);
8002DUK_INTERNAL_DECL void duk_hbuffer_decref_norz(duk_hthread *thr, duk_hbuffer *h);
8003DUK_INTERNAL_DECL void duk_hobject_decref(duk_hthread *thr, duk_hobject *h);
8004DUK_INTERNAL_DECL void duk_hobject_decref_norz(duk_hthread *thr, duk_hobject *h);
8005#endif
8006DUK_INTERNAL_DECL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h);
8007DUK_INTERNAL_DECL void duk_heaphdr_refzero_norz(duk_hthread *thr, duk_heaphdr *h);
8008#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
8009DUK_INTERNAL_DECL void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h); /* no 'norz' variant */
8010DUK_INTERNAL_DECL void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h); /* no 'norz' variant */
8011DUK_INTERNAL_DECL void duk_hobject_refzero(duk_hthread *thr, duk_hobject *h);
8012DUK_INTERNAL_DECL void duk_hobject_refzero_norz(duk_hthread *thr, duk_hobject *h);
8013#else
8014DUK_INTERNAL_DECL void duk_tval_incref(duk_tval *tv);
8015DUK_INTERNAL_DECL void duk_tval_decref(duk_hthread *thr, duk_tval *tv);
8016DUK_INTERNAL_DECL void duk_tval_decref_norz(duk_hthread *thr, duk_tval *tv);
8017DUK_INTERNAL_DECL void duk_heaphdr_incref(duk_heaphdr *h);
8018DUK_INTERNAL_DECL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h);
8019DUK_INTERNAL_DECL void duk_heaphdr_decref_norz(duk_hthread *thr, duk_heaphdr *h);
8020#endif
8021#else /* DUK_USE_REFERENCE_COUNTING */
8022/* no refcounting */
8023#endif /* DUK_USE_REFERENCE_COUNTING */
8024
8025DUK_INTERNAL_DECL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags);
8026
8027DUK_INTERNAL_DECL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len);
8028
8029#endif /* DUK_HEAP_H_INCLUDED */
8030/* #include duk_debugger.h */
8031#if !defined(DUK_DEBUGGER_H_INCLUDED)
8032#define DUK_DEBUGGER_H_INCLUDED
8033
8034/* Debugger protocol version is defined in the public API header. */
8035
8036/* Initial bytes for markers. */
8037#define DUK_DBG_IB_EOM 0x00
8038#define DUK_DBG_IB_REQUEST 0x01
8039#define DUK_DBG_IB_REPLY 0x02
8040#define DUK_DBG_IB_ERROR 0x03
8041#define DUK_DBG_IB_NOTIFY 0x04
8042
8043/* Other initial bytes. */
8044#define DUK_DBG_IB_INT4 0x10
8045#define DUK_DBG_IB_STR4 0x11
8046#define DUK_DBG_IB_STR2 0x12
8047#define DUK_DBG_IB_BUF4 0x13
8048#define DUK_DBG_IB_BUF2 0x14
8049#define DUK_DBG_IB_UNUSED 0x15
8050#define DUK_DBG_IB_UNDEFINED 0x16
8051#define DUK_DBG_IB_NULL 0x17
8052#define DUK_DBG_IB_TRUE 0x18
8053#define DUK_DBG_IB_FALSE 0x19
8054#define DUK_DBG_IB_NUMBER 0x1a
8055#define DUK_DBG_IB_OBJECT 0x1b
8056#define DUK_DBG_IB_POINTER 0x1c
8057#define DUK_DBG_IB_LIGHTFUNC 0x1d
8058#define DUK_DBG_IB_HEAPPTR 0x1e
8059/* The short string/integer initial bytes starting from 0x60 don't have
8060 * defines now.
8061 */
8062
8063/* Error codes. */
8064#define DUK_DBG_ERR_UNKNOWN 0x00
8065#define DUK_DBG_ERR_UNSUPPORTED 0x01
8066#define DUK_DBG_ERR_TOOMANY 0x02
8067#define DUK_DBG_ERR_NOTFOUND 0x03
8068#define DUK_DBG_ERR_APPLICATION 0x04
8069
8070/* Commands and notifys initiated by Duktape. */
8071#define DUK_DBG_CMD_STATUS 0x01
8072#define DUK_DBG_CMD_UNUSED_2 0x02 /* Duktape 1.x: print notify */
8073#define DUK_DBG_CMD_UNUSED_3 0x03 /* Duktape 1.x: alert notify */
8074#define DUK_DBG_CMD_UNUSED_4 0x04 /* Duktape 1.x: log notify */
8075#define DUK_DBG_CMD_THROW 0x05
8076#define DUK_DBG_CMD_DETACHING 0x06
8077#define DUK_DBG_CMD_APPNOTIFY 0x07
8078
8079/* Commands initiated by debug client. */
8080#define DUK_DBG_CMD_BASICINFO 0x10
8081#define DUK_DBG_CMD_TRIGGERSTATUS 0x11
8082#define DUK_DBG_CMD_PAUSE 0x12
8083#define DUK_DBG_CMD_RESUME 0x13
8084#define DUK_DBG_CMD_STEPINTO 0x14
8085#define DUK_DBG_CMD_STEPOVER 0x15
8086#define DUK_DBG_CMD_STEPOUT 0x16
8087#define DUK_DBG_CMD_LISTBREAK 0x17
8088#define DUK_DBG_CMD_ADDBREAK 0x18
8089#define DUK_DBG_CMD_DELBREAK 0x19
8090#define DUK_DBG_CMD_GETVAR 0x1a
8091#define DUK_DBG_CMD_PUTVAR 0x1b
8092#define DUK_DBG_CMD_GETCALLSTACK 0x1c
8093#define DUK_DBG_CMD_GETLOCALS 0x1d
8094#define DUK_DBG_CMD_EVAL 0x1e
8095#define DUK_DBG_CMD_DETACH 0x1f
8096#define DUK_DBG_CMD_DUMPHEAP 0x20
8097#define DUK_DBG_CMD_GETBYTECODE 0x21
8098#define DUK_DBG_CMD_APPREQUEST 0x22
8099#define DUK_DBG_CMD_GETHEAPOBJINFO 0x23
8100#define DUK_DBG_CMD_GETOBJPROPDESC 0x24
8101#define DUK_DBG_CMD_GETOBJPROPDESCRANGE 0x25
8102
8103/* The low 8 bits map directly to duk_hobject.h DUK_PROPDESC_FLAG_xxx.
8104 * The remaining flags are specific to the debugger.
8105 */
8106#define DUK_DBG_PROPFLAG_SYMBOL (1 << 8)
8107#define DUK_DBG_PROPFLAG_HIDDEN (1 << 9)
8108
8109#if defined(DUK_USE_DEBUGGER_SUPPORT)
8110DUK_INTERNAL_DECL void duk_debug_do_detach(duk_heap *heap);
8111
8112DUK_INTERNAL_DECL duk_bool_t duk_debug_read_peek(duk_hthread *thr);
8113DUK_INTERNAL_DECL void duk_debug_write_flush(duk_hthread *thr);
8114
8115DUK_INTERNAL_DECL void duk_debug_skip_bytes(duk_hthread *thr, duk_size_t length);
8116DUK_INTERNAL_DECL void duk_debug_skip_byte(duk_hthread *thr);
8117
8118DUK_INTERNAL_DECL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_size_t length);
8119DUK_INTERNAL_DECL duk_uint8_t duk_debug_read_byte(duk_hthread *thr);
8120DUK_INTERNAL_DECL duk_int32_t duk_debug_read_int(duk_hthread *thr);
8121DUK_INTERNAL_DECL duk_hstring *duk_debug_read_hstring(duk_hthread *thr);
8122/* XXX: exposed duk_debug_read_pointer */
8123/* XXX: exposed duk_debug_read_buffer */
8124/* XXX: exposed duk_debug_read_hbuffer */
8125#if 0
8126DUK_INTERNAL_DECL duk_heaphdr *duk_debug_read_heapptr(duk_hthread *thr);
8127#endif
8128#if defined(DUK_USE_DEBUGGER_INSPECT)
8129DUK_INTERNAL_DECL duk_heaphdr *duk_debug_read_any_ptr(duk_hthread *thr);
8130#endif
8131DUK_INTERNAL_DECL duk_tval *duk_debug_read_tval(duk_hthread *thr);
8132
8133DUK_INTERNAL_DECL void duk_debug_write_bytes(duk_hthread *thr, const duk_uint8_t *data, duk_size_t length);
8134DUK_INTERNAL_DECL void duk_debug_write_byte(duk_hthread *thr, duk_uint8_t x);
8135DUK_INTERNAL_DECL void duk_debug_write_unused(duk_hthread *thr);
8136DUK_INTERNAL_DECL void duk_debug_write_undefined(duk_hthread *thr);
8137#if defined(DUK_USE_DEBUGGER_INSPECT)
8138DUK_INTERNAL_DECL void duk_debug_write_null(duk_hthread *thr);
8139#endif
8140DUK_INTERNAL_DECL void duk_debug_write_boolean(duk_hthread *thr, duk_uint_t val);
8141DUK_INTERNAL_DECL void duk_debug_write_int(duk_hthread *thr, duk_int32_t x);
8142DUK_INTERNAL_DECL void duk_debug_write_uint(duk_hthread *thr, duk_uint32_t x);
8143DUK_INTERNAL_DECL void duk_debug_write_string(duk_hthread *thr, const char *data, duk_size_t length);
8144DUK_INTERNAL_DECL void duk_debug_write_cstring(duk_hthread *thr, const char *data);
8145DUK_INTERNAL_DECL void duk_debug_write_hstring(duk_hthread *thr, duk_hstring *h);
8146DUK_INTERNAL_DECL void duk_debug_write_buffer(duk_hthread *thr, const char *data, duk_size_t length);
8147DUK_INTERNAL_DECL void duk_debug_write_hbuffer(duk_hthread *thr, duk_hbuffer *h);
8148DUK_INTERNAL_DECL void duk_debug_write_pointer(duk_hthread *thr, void *ptr);
8149#if defined(DUK_USE_DEBUGGER_DUMPHEAP) || defined(DUK_USE_DEBUGGER_INSPECT)
8150DUK_INTERNAL_DECL void duk_debug_write_heapptr(duk_hthread *thr, duk_heaphdr *h);
8151#endif
8152DUK_INTERNAL_DECL void duk_debug_write_hobject(duk_hthread *thr, duk_hobject *obj);
8153DUK_INTERNAL_DECL void duk_debug_write_tval(duk_hthread *thr, duk_tval *tv);
8154#if 0 /* unused */
8155DUK_INTERNAL_DECL void duk_debug_write_request(duk_hthread *thr, duk_small_uint_t command);
8156#endif
8157DUK_INTERNAL_DECL void duk_debug_write_reply(duk_hthread *thr);
8158DUK_INTERNAL_DECL void duk_debug_write_error_eom(duk_hthread *thr, duk_small_uint_t err_code, const char *msg);
8159DUK_INTERNAL_DECL void duk_debug_write_notify(duk_hthread *thr, duk_small_uint_t command);
8160DUK_INTERNAL_DECL void duk_debug_write_eom(duk_hthread *thr);
8161
8162DUK_INTERNAL_DECL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr);
8163DUK_INTERNAL_DECL void duk_debug_send_status(duk_hthread *thr);
8164#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY)
8165DUK_INTERNAL_DECL void duk_debug_send_throw(duk_hthread *thr, duk_bool_t fatal);
8166#endif
8167
8168DUK_INTERNAL_DECL void duk_debug_halt_execution(duk_hthread *thr, duk_bool_t use_prev_pc);
8169DUK_INTERNAL_DECL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t no_block);
8170
8171DUK_INTERNAL_DECL duk_small_int_t duk_debug_add_breakpoint(duk_hthread *thr, duk_hstring *filename, duk_uint32_t line);
8172DUK_INTERNAL_DECL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_uint_t breakpoint_index);
8173#endif
8174
8175#endif /* DUK_DEBUGGER_H_INCLUDED */
8176/* #include duk_debug.h */
8177/*
8178 * Debugging macros, DUK_DPRINT() and its variants in particular.
8179 *
8180 * DUK_DPRINT() allows formatted debug prints, and supports standard
8181 * and Duktape specific formatters. See duk_debug_vsnprintf.c for details.
8182 *
8183 * DUK_D(x), DUK_DD(x), and DUK_DDD(x) are used together with log macros
8184 * for technical reasons. They are concretely used to hide 'x' from the
8185 * compiler when the corresponding log level is disabled. This allows
8186 * clean builds on non-C99 compilers, at the cost of more verbose code.
8187 * Examples:
8188 *
8189 * DUK_D(DUK_DPRINT("foo"));
8190 * DUK_DD(DUK_DDPRINT("foo"));
8191 * DUK_DDD(DUK_DDDPRINT("foo"));
8192 *
8193 * This approach is preferable to the old "double parentheses" hack because
8194 * double parentheses make the C99 solution worse: __FILE__ and __LINE__ can
8195 * no longer be added transparently without going through globals, which
8196 * works poorly with threading.
8197 */
8198
8199#if !defined(DUK_DEBUG_H_INCLUDED)
8200#define DUK_DEBUG_H_INCLUDED
8201
8202#if defined(DUK_USE_DEBUG)
8203
8204#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0)
8205#define DUK_D(x) x
8206#else
8207#define DUK_D(x) do { } while (0) /* omit */
8208#endif
8209
8210#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
8211#define DUK_DD(x) x
8212#else
8213#define DUK_DD(x) do { } while (0) /* omit */
8214#endif
8215
8216#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
8217#define DUK_DDD(x) x
8218#else
8219#define DUK_DDD(x) do { } while (0) /* omit */
8220#endif
8221
8222/*
8223 * Exposed debug macros: debugging enabled
8224 */
8225
8226#if defined(DUK_USE_VARIADIC_MACROS)
8227
8228/* Note: combining __FILE__, __LINE__, and __func__ into fmt would be
8229 * possible compile time, but waste some space with shared function names.
8230 */
8231#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__);
8232
8233#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0)
8234#define DUK_DPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DEBUG, __VA_ARGS__)
8235#else
8236#define DUK_DPRINT(...)
8237#endif
8238
8239#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
8240#define DUK_DDPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DDEBUG, __VA_ARGS__)
8241#else
8242#define DUK_DDPRINT(...)
8243#endif
8244
8245#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
8246#define DUK_DDDPRINT(...) DUK__DEBUG_LOG(DUK_LEVEL_DDDEBUG, __VA_ARGS__)
8247#else
8248#define DUK_DDDPRINT(...)
8249#endif
8250
8251#else /* DUK_USE_VARIADIC_MACROS */
8252
8253#define DUK__DEBUG_STASH(lev) \
8254 (void) DUK_SNPRINTF(duk_debug_file_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FILE_MACRO), \
8255 (void) (duk_debug_file_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0), \
8256 (void) (duk_debug_line_stash = (duk_int_t) DUK_LINE_MACRO), \
8257 (void) DUK_SNPRINTF(duk_debug_func_stash, DUK_DEBUG_STASH_SIZE, "%s", (const char *) DUK_FUNC_MACRO), \
8258 (void) (duk_debug_func_stash[DUK_DEBUG_STASH_SIZE - 1] = (char) 0), \
8259 (void) (duk_debug_level_stash = (lev))
8260
8261/* Without variadic macros resort to comma expression trickery to handle debug
8262 * prints. This generates a lot of harmless warnings. These hacks are not
8263 * needed normally because DUK_D() and friends will hide the entire debug log
8264 * statement from the compiler.
8265 */
8266
8267#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 0)
8268#define DUK_DPRINT DUK__DEBUG_STASH(DUK_LEVEL_DEBUG), (void) duk_debug_log /* args go here in parens */
8269#else
8270#define DUK_DPRINT 0 && /* args go here as a comma expression in parens */
8271#endif
8272
8273#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
8274#define DUK_DDPRINT DUK__DEBUG_STASH(DUK_LEVEL_DDEBUG), (void) duk_debug_log /* args go here in parens */
8275#else
8276#define DUK_DDPRINT 0 && /* args */
8277#endif
8278
8279#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
8280#define DUK_DDDPRINT DUK__DEBUG_STASH(DUK_LEVEL_DDDEBUG), (void) duk_debug_log /* args go here in parens */
8281#else
8282#define DUK_DDDPRINT 0 && /* args */
8283#endif
8284
8285#endif /* DUK_USE_VARIADIC_MACROS */
8286
8287#else /* DUK_USE_DEBUG */
8288
8289/*
8290 * Exposed debug macros: debugging disabled
8291 */
8292
8293#define DUK_D(x) do { } while (0) /* omit */
8294#define DUK_DD(x) do { } while (0) /* omit */
8295#define DUK_DDD(x) do { } while (0) /* omit */
8296
8297#if defined(DUK_USE_VARIADIC_MACROS)
8298
8299#define DUK_DPRINT(...)
8300#define DUK_DDPRINT(...)
8301#define DUK_DDDPRINT(...)
8302
8303#else /* DUK_USE_VARIADIC_MACROS */
8304
8305#define DUK_DPRINT 0 && /* args go here as a comma expression in parens */
8306#define DUK_DDPRINT 0 && /* args */
8307#define DUK_DDDPRINT 0 && /* args */
8308
8309#endif /* DUK_USE_VARIADIC_MACROS */
8310
8311#endif /* DUK_USE_DEBUG */
8312
8313/*
8314 * Structs
8315 */
8316
8317#if defined(DUK_USE_DEBUG)
8318struct duk_fixedbuffer {
8319 duk_uint8_t *buffer;
8320 duk_size_t length;
8321 duk_size_t offset;
8322 duk_bool_t truncated;
8323};
8324#endif
8325
8326/*
8327 * Prototypes
8328 */
8329
8330#if defined(DUK_USE_DEBUG)
8331DUK_INTERNAL_DECL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const char *format, va_list ap);
8332#if 0 /*unused*/
8333DUK_INTERNAL_DECL duk_int_t duk_debug_snprintf(char *str, duk_size_t size, const char *format, ...);
8334#endif
8335DUK_INTERNAL_DECL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_uint8_t *fptr, duk_size_t fptr_size);
8336
8337#if defined(DUK_USE_VARIADIC_MACROS)
8338DUK_INTERNAL_DECL void duk_debug_log(duk_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...);
8339#else /* DUK_USE_VARIADIC_MACROS */
8340/* parameter passing, not thread safe */
8341#define DUK_DEBUG_STASH_SIZE 128
8342#if !defined(DUK_SINGLE_FILE)
8343DUK_INTERNAL_DECL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE];
8344DUK_INTERNAL_DECL duk_int_t duk_debug_line_stash;
8345DUK_INTERNAL_DECL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE];
8346DUK_INTERNAL_DECL duk_int_t duk_debug_level_stash;
8347#endif
8348DUK_INTERNAL_DECL void duk_debug_log(const char *fmt, ...);
8349#endif /* DUK_USE_VARIADIC_MACROS */
8350
8351DUK_INTERNAL_DECL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffer, duk_size_t length);
8352DUK_INTERNAL_DECL void duk_fb_put_byte(duk_fixedbuffer *fb, duk_uint8_t x);
8353DUK_INTERNAL_DECL void duk_fb_put_cstring(duk_fixedbuffer *fb, const char *x);
8354DUK_INTERNAL_DECL void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...);
8355DUK_INTERNAL_DECL void duk_fb_put_funcptr(duk_fixedbuffer *fb, duk_uint8_t *fptr, duk_size_t fptr_size);
8356DUK_INTERNAL_DECL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb);
8357
8358#endif /* DUK_USE_DEBUG */
8359
8360#endif /* DUK_DEBUG_H_INCLUDED */
8361/* #include duk_error.h */
8362/*
8363 * Error handling macros, assertion macro, error codes.
8364 *
8365 * There are three types of 'errors':
8366 *
8367 * 1. Ordinary errors relative to a thread, cause a longjmp, catchable.
8368 * 2. Fatal errors relative to a heap, cause fatal handler to be called.
8369 * 3. Fatal errors without context, cause the default (not heap specific)
8370 * fatal handler to be called.
8371 *
8372 * Fatal errors without context are used by debug code such as assertions.
8373 * By providing a fatal error handler for a Duktape heap, user code can
8374 * avoid fatal errors without context in non-debug builds.
8375 */
8376
8377#if !defined(DUK_ERROR_H_INCLUDED)
8378#define DUK_ERROR_H_INCLUDED
8379
8380/*
8381 * Error codes: defined in duktape.h
8382 *
8383 * Error codes are used as a shorthand to throw exceptions from inside
8384 * the implementation. The appropriate Ecmascript object is constructed
8385 * based on the code. Ecmascript code throws objects directly. The error
8386 * codes are defined in the public API header because they are also used
8387 * by calling code.
8388 */
8389
8390/*
8391 * Normal error
8392 *
8393 * Normal error is thrown with a longjmp() through the current setjmp()
8394 * catchpoint record in the duk_heap. The 'curr_thread' of the duk_heap
8395 * identifies the throwing thread.
8396 *
8397 * Error formatting is usually unnecessary. The error macros provide a
8398 * zero argument version (no formatting) and separate macros for small
8399 * argument counts. Variadic macros are not used to avoid portability
8400 * issues and avoid the need for stash-based workarounds when they're not
8401 * available. Vararg calls are avoided for non-formatted error calls
8402 * because vararg call sites are larger than normal, and there are a lot
8403 * of call sites with no formatting.
8404 *
8405 * Note that special formatting provided by debug macros is NOT available.
8406 *
8407 * The _RAW variants allow the caller to specify file and line. This makes
8408 * it easier to write checked calls which want to use the call site of the
8409 * checked function, not the error macro call inside the checked function.
8410 */
8411
8412#if defined(DUK_USE_VERBOSE_ERRORS)
8413
8414/* Because there are quite many call sites, pack error code (require at most
8415 * 8-bit) into a single argument.
8416 */
8417#define DUK_ERROR(thr,err,msg) do { \
8418 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
8419 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
8420 duk_err_handle_error((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (msg)); \
8421 } while (0)
8422#define DUK_ERROR_RAW(thr,file,line,err,msg) do { \
8423 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
8424 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
8425 duk_err_handle_error((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (msg)); \
8426 } while (0)
8427
8428#define DUK_ERROR_FMT1(thr,err,fmt,arg1) do { \
8429 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
8430 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
8431 duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1)); \
8432 } while (0)
8433#define DUK_ERROR_RAW_FMT1(thr,file,line,err,fmt,arg1) do { \
8434 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
8435 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
8436 duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1)); \
8437 } while (0)
8438
8439#define DUK_ERROR_FMT2(thr,err,fmt,arg1,arg2) do { \
8440 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
8441 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
8442 duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2)); \
8443 } while (0)
8444#define DUK_ERROR_RAW_FMT2(thr,file,line,err,fmt,arg1,arg2) do { \
8445 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
8446 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
8447 duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2)); \
8448 } while (0)
8449
8450#define DUK_ERROR_FMT3(thr,err,fmt,arg1,arg2,arg3) do { \
8451 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
8452 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
8453 duk_err_handle_error_fmt((thr), DUK_FILE_MACRO, (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3)); \
8454 } while (0)
8455#define DUK_ERROR_RAW_FMT3(thr,file,line,err,fmt,arg1,arg2,arg3) do { \
8456 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
8457 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
8458 duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3)); \
8459 } while (0)
8460
8461#define DUK_ERROR_FMT4(thr,err,fmt,arg1,arg2,arg3,arg4) do { \
8462 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) DUK_LINE_MACRO; \
8463 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
8464 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)); \
8465 } while (0)
8466#define DUK_ERROR_RAW_FMT4(thr,file,line,err,fmt,arg1,arg2,arg3,arg4) do { \
8467 duk_errcode_t duk__err = (err); duk_int_t duk__line = (duk_int_t) (line); \
8468 DUK_ASSERT(duk__err >= 0 && duk__err <= 0xff); DUK_ASSERT(duk__line >= 0 && duk__line <= 0x00ffffffL); \
8469 duk_err_handle_error_fmt((thr), (file), (((duk_uint_t) duk__err) << 24) | ((duk_uint_t) duk__line), (fmt), (arg1), (arg2), (arg3), (arg4)); \
8470 } while (0)
8471
8472#else /* DUK_USE_VERBOSE_ERRORS */
8473
8474#define DUK_ERROR(thr,err,msg) duk_err_handle_error((thr), (err))
8475#define DUK_ERROR_RAW(thr,file,line,err,msg) duk_err_handle_error((thr), (err))
8476
8477#define DUK_ERROR_FMT1(thr,err,fmt,arg1) DUK_ERROR((thr),(err),(fmt))
8478#define DUK_ERROR_RAW_FMT1(thr,file,line,err,fmt,arg1) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
8479
8480#define DUK_ERROR_FMT2(thr,err,fmt,arg1,arg2) DUK_ERROR((thr),(err),(fmt))
8481#define DUK_ERROR_RAW_FMT2(thr,file,line,err,fmt,arg1,arg2) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
8482
8483#define DUK_ERROR_FMT3(thr,err,fmt,arg1,arg2,arg3) DUK_ERROR((thr),(err),(fmt))
8484#define DUK_ERROR_RAW_FMT3(thr,file,line,err,fmt,arg1,arg2,arg3) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
8485
8486#define DUK_ERROR_FMT4(thr,err,fmt,arg1,arg2,arg3,arg4) DUK_ERROR((thr),(err),(fmt))
8487#define DUK_ERROR_RAW_FMT4(thr,file,line,err,fmt,arg1,arg2,arg3,arg4) DUK_ERROR_RAW((thr),(file),(line),(err),(fmt))
8488
8489#endif /* DUK_USE_VERBOSE_ERRORS */
8490
8491/*
8492 * Fatal error without context
8493 *
8494 * The macro is an expression to make it compatible with DUK_ASSERT_EXPR().
8495 */
8496
8497#define DUK_FATAL_WITHOUT_CONTEXT(msg) \
8498 duk_default_fatal_handler(NULL, (msg))
8499
8500/*
8501 * Error throwing helpers
8502 *
8503 * The goal is to provide verbose and configurable error messages. Call
8504 * sites should be clean in source code and compile to a small footprint.
8505 * Small footprint is also useful for performance because small cold paths
8506 * reduce code cache pressure. Adding macros here only makes sense if there
8507 * are enough call sites to get concrete benefits.
8508 *
8509 * DUK_ERROR_xxx() macros are generic and can be used anywhere.
8510 *
8511 * DUK_DCERROR_xxx() macros can only be used in Duktape/C functions where
8512 * the "return DUK_RET_xxx;" shorthand is available for low memory targets.
8513 * The DUK_DCERROR_xxx() macros always either throw or perform a
8514 * 'return DUK_RET_xxx' from the calling function.
8515 */
8516
8517#if defined(DUK_USE_VERBOSE_ERRORS)
8518/* Verbose errors with key/value summaries (non-paranoid) or without key/value
8519 * summaries (paranoid, for some security sensitive environments), the paranoid
8520 * vs. non-paranoid distinction affects only a few specific errors.
8521 */
8522#if defined(DUK_USE_PARANOID_ERRORS)
8523#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,idx,expectname,lowmemstr) do { \
8524 duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (idx), (expectname)); \
8525 } while (0)
8526#else /* DUK_USE_PARANOID_ERRORS */
8527#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,idx,expectname,lowmemstr) do { \
8528 duk_err_require_type_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (idx), (expectname)); \
8529 } while (0)
8530#endif /* DUK_USE_PARANOID_ERRORS */
8531
8532#define DUK_ERROR_INTERNAL(thr) do { \
8533 duk_err_error_internal((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
8534 } while (0)
8535#define DUK_ERROR_ALLOC_FAILED(thr) do { \
8536 duk_err_error_alloc_failed((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
8537 } while (0)
8538#define DUK_ERROR_UNSUPPORTED(thr) do { \
8539 DUK_ERROR((thr), DUK_ERR_ERROR, DUK_STR_UNSUPPORTED); \
8540 } while (0)
8541#define DUK_ERROR_ERROR(thr,msg) do { \
8542 duk_err_error((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
8543 } while (0)
8544#define DUK_ERROR_RANGE_INDEX(thr,idx) do { \
8545 duk_err_range_index((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (idx)); \
8546 } while (0)
8547#define DUK_ERROR_RANGE_PUSH_BEYOND(thr) do { \
8548 duk_err_range_push_beyond((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
8549 } while (0)
8550#define DUK_ERROR_RANGE_INVALID_ARGS(thr) do { \
8551 DUK_ERROR_RANGE((thr), DUK_STR_INVALID_ARGS); \
8552 } while (0)
8553#define DUK_DCERROR_RANGE_INVALID_ARGS(thr) do { \
8554 DUK_ERROR_RANGE_INVALID_ARGS((thr)); \
8555 return 0; \
8556 } while (0)
8557#define DUK_ERROR_RANGE_INVALID_COUNT(thr) do { \
8558 DUK_ERROR_RANGE((thr), DUK_STR_INVALID_COUNT); \
8559 } while (0)
8560#define DUK_ERROR_RANGE_INVALID_LENGTH(thr) do { \
8561 DUK_ERROR_RANGE((thr), DUK_STR_INVALID_LENGTH); \
8562 } while (0)
8563#define DUK_DCERROR_RANGE_INVALID_LENGTH(thr) do { \
8564 DUK_ERROR_RANGE_INVALID_LENGTH((thr)); \
8565 return 0; \
8566 } while (0)
8567#define DUK_ERROR_RANGE(thr,msg) do { \
8568 duk_err_range((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO, (msg)); \
8569 } while (0)
8570#define DUK_ERROR_EVAL(thr,msg) do { \
8571 DUK_ERROR((thr), DUK_ERR_EVAL_ERROR, (msg)); \
8572 } while (0)
8573#define DUK_ERROR_REFERENCE(thr,msg) do { \
8574 DUK_ERROR((thr), DUK_ERR_REFERENCE_ERROR, (msg)); \
8575 } while (0)
8576#define DUK_ERROR_SYNTAX(thr,msg) do { \
8577 DUK_ERROR((thr), DUK_ERR_SYNTAX_ERROR, (msg)); \
8578 } while (0)
8579#define DUK_ERROR_TYPE_INVALID_ARGS(thr) do { \
8580 duk_err_type_invalid_args((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
8581 } while (0)
8582#define DUK_DCERROR_TYPE_INVALID_ARGS(thr) do { \
8583 DUK_ERROR_TYPE_INVALID_ARGS((thr)); \
8584 return 0; \
8585 } while (0)
8586#define DUK_ERROR_TYPE_INVALID_STATE(thr) do { \
8587 duk_err_type_invalid_state((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
8588 } while (0)
8589#define DUK_DCERROR_TYPE_INVALID_STATE(thr) do { \
8590 DUK_ERROR_TYPE_INVALID_STATE((thr)); \
8591 return 0; \
8592 } while (0)
8593#define DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
8594 duk_err_type_invalid_trap_result((thr), DUK_FILE_MACRO, (duk_int_t) DUK_LINE_MACRO); \
8595 } while (0)
8596#define DUK_DCERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
8597 DUK_ERROR_TYPE((thr), DUK_STR_INVALID_TRAP_RESULT); \
8598 } while (0)
8599#define DUK_ERROR_TYPE(thr,msg) do { \
8600 DUK_ERROR((thr), DUK_ERR_TYPE_ERROR, (msg)); \
8601 } while (0)
8602#define DUK_ERROR_URI(thr,msg) do { \
8603 DUK_ERROR((thr), DUK_ERR_URI_ERROR, (msg)); \
8604 } while (0)
8605#else /* DUK_USE_VERBOSE_ERRORS */
8606/* Non-verbose errors for low memory targets: no file, line, or message. */
8607
8608#define DUK_ERROR_REQUIRE_TYPE_INDEX(thr,idx,expectname,lowmemstr) do { \
8609 duk_err_type((thr)); \
8610 } while (0)
8611
8612#define DUK_ERROR_INTERNAL(thr) do { \
8613 duk_err_error((thr)); \
8614 } while (0)
8615#define DUK_ERROR_ALLOC_FAILED(thr) do { \
8616 duk_err_error((thr)); \
8617 } while (0)
8618#define DUK_ERROR_UNSUPPORTED(thr) do { \
8619 duk_err_error((thr)); \
8620 } while (0)
8621#define DUK_ERROR_ERROR(thr,msg) do { \
8622 duk_err_error((thr)); \
8623 } while (0)
8624#define DUK_ERROR_RANGE_INDEX(thr,idx) do { \
8625 duk_err_range((thr)); \
8626 } while (0)
8627#define DUK_ERROR_RANGE_PUSH_BEYOND(thr) do { \
8628 duk_err_range((thr)); \
8629 } while (0)
8630#define DUK_ERROR_RANGE_INVALID_ARGS(thr) do { \
8631 duk_err_range((thr)); \
8632 } while (0)
8633#define DUK_DCERROR_RANGE_INVALID_ARGS(thr) do { \
8634 DUK_UNREF((thr)); \
8635 return DUK_RET_RANGE_ERROR; \
8636 } while (0)
8637#define DUK_ERROR_RANGE_INVALID_COUNT(thr) do { \
8638 duk_err_range((thr)); \
8639 } while (0)
8640#define DUK_ERROR_RANGE_INVALID_LENGTH(thr) do { \
8641 duk_err_range((thr)); \
8642 } while (0)
8643#define DUK_DCERROR_RANGE_INVALID_LENGTH(thr) do { \
8644 DUK_UNREF((thr)); \
8645 return DUK_RET_RANGE_ERROR; \
8646 } while (0)
8647#define DUK_ERROR_RANGE(thr,msg) do { \
8648 duk_err_range((thr)); \
8649 } while (0)
8650#define DUK_ERROR_EVAL(thr,msg) do { \
8651 duk_err_eval((thr)); \
8652 } while (0)
8653#define DUK_ERROR_REFERENCE(thr,msg) do { \
8654 duk_err_reference((thr)); \
8655 } while (0)
8656#define DUK_ERROR_SYNTAX(thr,msg) do { \
8657 duk_err_syntax((thr)); \
8658 } while (0)
8659#define DUK_ERROR_TYPE_INVALID_ARGS(thr) do { \
8660 duk_err_type((thr)); \
8661 } while (0)
8662#define DUK_DCERROR_TYPE_INVALID_ARGS(thr) do { \
8663 DUK_UNREF((thr)); \
8664 return DUK_RET_TYPE_ERROR; \
8665 } while (0)
8666#define DUK_ERROR_TYPE_INVALID_STATE(thr) do { \
8667 duk_err_type((thr)); \
8668 } while (0)
8669#define DUK_DCERROR_TYPE_INVALID_STATE(thr) do { \
8670 duk_err_type((thr)); \
8671 } while (0)
8672#define DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
8673 duk_err_type((thr)); \
8674 } while (0)
8675#define DUK_DCERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
8676 DUK_UNREF((thr)); \
8677 return DUK_RET_TYPE_ERROR; \
8678 } while (0)
8679#define DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr) do { \
8680 duk_err_type((thr)); \
8681 } while (0)
8682#define DUK_ERROR_TYPE(thr,msg) do { \
8683 duk_err_type((thr)); \
8684 } while (0)
8685#define DUK_ERROR_URI(thr,msg) do { \
8686 duk_err_uri((thr)); \
8687 } while (0)
8688#endif /* DUK_USE_VERBOSE_ERRORS */
8689
8690/*
8691 * Assert macro: failure causes a fatal error.
8692 *
8693 * NOTE: since the assert macro doesn't take a heap/context argument, there's
8694 * no way to look up a heap/context specific fatal error handler which may have
8695 * been given by the application. Instead, assertion failures always use the
8696 * internal default fatal error handler; it can be replaced via duk_config.h
8697 * and then applies to all Duktape heaps.
8698 */
8699
8700#if defined(DUK_USE_ASSERTIONS)
8701
8702/* The message should be a compile time constant without formatting (less risk);
8703 * we don't care about assertion text size because they're not used in production
8704 * builds.
8705 */
8706#define DUK_ASSERT(x) do { \
8707 if (!(x)) { \
8708 DUK_FATAL_WITHOUT_CONTEXT("assertion failed: " #x \
8709 " (" DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO) ")"); \
8710 } \
8711 } while (0)
8712
8713/* Assertion compatible inside a comma expression, evaluates to void. */
8714#define DUK_ASSERT_EXPR(x) \
8715 ((void) ((x) ? 0 : (DUK_FATAL_WITHOUT_CONTEXT("assertion failed: " #x \
8716 " (" DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO) ")"), 0)))
8717
8718#else /* DUK_USE_ASSERTIONS */
8719
8720#define DUK_ASSERT(x) do { /* assertion omitted */ } while (0)
8721
8722#define DUK_ASSERT_EXPR(x) ((void) 0)
8723
8724#endif /* DUK_USE_ASSERTIONS */
8725
8726/* this variant is used when an assert would generate a compile warning by
8727 * being always true (e.g. >= 0 comparison for an unsigned value
8728 */
8729#define DUK_ASSERT_DISABLE(x) do { /* assertion disabled */ } while (0)
8730
8731/*
8732 * Assertion helpers
8733 */
8734
8735#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_REFERENCE_COUNTING)
8736#define DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(h) do { \
8737 DUK_ASSERT((h) == NULL || DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) (h)) > 0); \
8738 } while (0)
8739#define DUK_ASSERT_REFCOUNT_NONZERO_TVAL(tv) do { \
8740 if ((tv) != NULL && DUK_TVAL_IS_HEAP_ALLOCATED((tv))) { \
8741 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(DUK_TVAL_GET_HEAPHDR((tv))) > 0); \
8742 } \
8743 } while (0)
8744#else
8745#define DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(h) /* no refcount check */
8746#define DUK_ASSERT_REFCOUNT_NONZERO_TVAL(tv) /* no refcount check */
8747#endif
8748
8749#define DUK_ASSERT_TOP(ctx,n) DUK_ASSERT((duk_idx_t) duk_get_top((ctx)) == (duk_idx_t) (n))
8750
8751#if defined(DUK_USE_ASSERTIONS) && defined(DUK_USE_PACKED_TVAL)
8752#define DUK_ASSERT_DOUBLE_IS_NORMALIZED(dval) do { \
8753 duk_double_union duk__assert_tmp_du; \
8754 duk__assert_tmp_du.d = (dval); \
8755 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&duk__assert_tmp_du)); \
8756 } while (0)
8757#else
8758#define DUK_ASSERT_DOUBLE_IS_NORMALIZED(dval) /* nop */
8759#endif
8760
8761#define DUK_ASSERT_VS_SPACE(thr) \
8762 DUK_ASSERT(thr->valstack_top < thr->valstack_end)
8763
8764/*
8765 * Helper for valstack space
8766 *
8767 * Caller of DUK_ASSERT_VALSTACK_SPACE() estimates the number of free stack entries
8768 * required for its own use, and any child calls which are not (a) Duktape API calls
8769 * or (b) Duktape calls which involve extending the valstack (e.g. getter call).
8770 */
8771
8772#define DUK_VALSTACK_ASSERT_EXTRA 5 /* this is added to checks to allow for Duktape
8773 * API calls in addition to function's own use
8774 */
8775#if defined(DUK_USE_ASSERTIONS)
8776#define DUK_ASSERT_VALSTACK_SPACE(thr,n) do { \
8777 DUK_ASSERT((thr) != NULL); \
8778 DUK_ASSERT((thr)->valstack_end - (thr)->valstack_top >= (n) + DUK_VALSTACK_ASSERT_EXTRA); \
8779 } while (0)
8780#else
8781#define DUK_ASSERT_VALSTACK_SPACE(thr,n) /* no valstack space check */
8782#endif
8783
8784/*
8785 * Prototypes
8786 */
8787
8788#if defined(DUK_USE_VERBOSE_ERRORS)
8789DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *msg));
8790DUK_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, ...));
8791#else /* DUK_USE_VERBOSE_ERRORS */
8792DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code));
8793#endif /* DUK_USE_VERBOSE_ERRORS */
8794
8795#if defined(DUK_USE_VERBOSE_ERRORS)
8796DUK_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));
8797#else
8798DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code));
8799#endif
8800
8801DUK_NORETURN(DUK_INTERNAL_DECL void duk_error_throw_from_negative_rc(duk_hthread *thr, duk_ret_t rc));
8802
8803#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
8804DUK_INTERNAL_DECL void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *filename, duk_int_t line, duk_bool_t noblame_fileline);
8805#endif
8806#if defined(DUK_USE_AUGMENT_ERROR_THROW)
8807DUK_INTERNAL_DECL void duk_err_augment_error_throw(duk_hthread *thr);
8808#endif
8809
8810#if defined(DUK_USE_VERBOSE_ERRORS)
8811#if defined(DUK_USE_PARANOID_ERRORS)
8812DUK_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));
8813#else
8814DUK_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));
8815#endif
8816DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber));
8817DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error_alloc_failed(duk_hthread *thr, const char *filename, duk_int_t linenumber));
8818DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
8819DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx));
8820DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range_push_beyond(duk_hthread *thr, const char *filename, duk_int_t linenumber));
8821DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message));
8822DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type_invalid_args(duk_hthread *thr, const char *filename, duk_int_t linenumber));
8823DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type_invalid_state(duk_hthread *thr, const char *filename, duk_int_t linenumber));
8824DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type_invalid_trap_result(duk_hthread *thr, const char *filename, duk_int_t linenumber));
8825#else /* DUK_VERBOSE_ERRORS */
8826DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_error(duk_hthread *thr));
8827DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_range(duk_hthread *thr));
8828DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_eval(duk_hthread *thr));
8829DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_reference(duk_hthread *thr));
8830DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_syntax(duk_hthread *thr));
8831DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_type(duk_hthread *thr));
8832DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_uri(duk_hthread *thr));
8833#endif /* DUK_VERBOSE_ERRORS */
8834
8835DUK_NORETURN(DUK_INTERNAL_DECL void duk_err_longjmp(duk_hthread *thr));
8836
8837DUK_NORETURN(DUK_INTERNAL_DECL void duk_default_fatal_handler(void *udata, const char *msg));
8838
8839DUK_INTERNAL_DECL void duk_err_setup_heap_ljstate(duk_hthread *thr, duk_small_int_t lj_type);
8840
8841DUK_INTERNAL_DECL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, duk_errcode_t err_code);
8842
8843#endif /* DUK_ERROR_H_INCLUDED */
8844/* #include duk_unicode.h */
8845/*
8846 * Unicode helpers
8847 */
8848
8849#if !defined(DUK_UNICODE_H_INCLUDED)
8850#define DUK_UNICODE_H_INCLUDED
8851
8852/*
8853 * UTF-8 / XUTF-8 / CESU-8 constants
8854 */
8855
8856#define DUK_UNICODE_MAX_XUTF8_LENGTH 7 /* up to 36 bit codepoints */
8857#define DUK_UNICODE_MAX_XUTF8_BMP_LENGTH 3 /* all codepoints up to U+FFFF */
8858#define DUK_UNICODE_MAX_CESU8_LENGTH 6 /* all codepoints up to U+10FFFF */
8859#define DUK_UNICODE_MAX_CESU8_BMP_LENGTH 3 /* all codepoints up to U+FFFF */
8860
8861/*
8862 * Useful Unicode codepoints
8863 *
8864 * Integer constants must be signed to avoid unexpected coercions
8865 * in comparisons.
8866 */
8867
8868#define DUK_UNICODE_CP_ZWNJ 0x200cL /* zero-width non-joiner */
8869#define DUK_UNICODE_CP_ZWJ 0x200dL /* zero-width joiner */
8870#define DUK_UNICODE_CP_REPLACEMENT_CHARACTER 0xfffdL /* http://en.wikipedia.org/wiki/Replacement_character#Replacement_character */
8871
8872/*
8873 * ASCII character constants
8874 *
8875 * C character literals like 'x' have a platform specific value and do
8876 * not match ASCII (UTF-8) values on e.g. EBCDIC platforms. So, use
8877 * these (admittedly awkward) constants instead. These constants must
8878 * also have signed values to avoid unexpected coercions in comparisons.
8879 *
8880 * http://en.wikipedia.org/wiki/ASCII
8881 */
8882
8883#define DUK_ASC_NUL 0x00
8884#define DUK_ASC_SOH 0x01
8885#define DUK_ASC_STX 0x02
8886#define DUK_ASC_ETX 0x03
8887#define DUK_ASC_EOT 0x04
8888#define DUK_ASC_ENQ 0x05
8889#define DUK_ASC_ACK 0x06
8890#define DUK_ASC_BEL 0x07
8891#define DUK_ASC_BS 0x08
8892#define DUK_ASC_HT 0x09
8893#define DUK_ASC_LF 0x0a
8894#define DUK_ASC_VT 0x0b
8895#define DUK_ASC_FF 0x0c
8896#define DUK_ASC_CR 0x0d
8897#define DUK_ASC_SO 0x0e
8898#define DUK_ASC_SI 0x0f
8899#define DUK_ASC_DLE 0x10
8900#define DUK_ASC_DC1 0x11
8901#define DUK_ASC_DC2 0x12
8902#define DUK_ASC_DC3 0x13
8903#define DUK_ASC_DC4 0x14
8904#define DUK_ASC_NAK 0x15
8905#define DUK_ASC_SYN 0x16
8906#define DUK_ASC_ETB 0x17
8907#define DUK_ASC_CAN 0x18
8908#define DUK_ASC_EM 0x19
8909#define DUK_ASC_SUB 0x1a
8910#define DUK_ASC_ESC 0x1b
8911#define DUK_ASC_FS 0x1c
8912#define DUK_ASC_GS 0x1d
8913#define DUK_ASC_RS 0x1e
8914#define DUK_ASC_US 0x1f
8915#define DUK_ASC_SPACE 0x20
8916#define DUK_ASC_EXCLAMATION 0x21
8917#define DUK_ASC_DOUBLEQUOTE 0x22
8918#define DUK_ASC_HASH 0x23
8919#define DUK_ASC_DOLLAR 0x24
8920#define DUK_ASC_PERCENT 0x25
8921#define DUK_ASC_AMP 0x26
8922#define DUK_ASC_SINGLEQUOTE 0x27
8923#define DUK_ASC_LPAREN 0x28
8924#define DUK_ASC_RPAREN 0x29
8925#define DUK_ASC_STAR 0x2a
8926#define DUK_ASC_PLUS 0x2b
8927#define DUK_ASC_COMMA 0x2c
8928#define DUK_ASC_MINUS 0x2d
8929#define DUK_ASC_PERIOD 0x2e
8930#define DUK_ASC_SLASH 0x2f
8931#define DUK_ASC_0 0x30
8932#define DUK_ASC_1 0x31
8933#define DUK_ASC_2 0x32
8934#define DUK_ASC_3 0x33
8935#define DUK_ASC_4 0x34
8936#define DUK_ASC_5 0x35
8937#define DUK_ASC_6 0x36
8938#define DUK_ASC_7 0x37
8939#define DUK_ASC_8 0x38
8940#define DUK_ASC_9 0x39
8941#define DUK_ASC_COLON 0x3a
8942#define DUK_ASC_SEMICOLON 0x3b
8943#define DUK_ASC_LANGLE 0x3c
8944#define DUK_ASC_EQUALS 0x3d
8945#define DUK_ASC_RANGLE 0x3e
8946#define DUK_ASC_QUESTION 0x3f
8947#define DUK_ASC_ATSIGN 0x40
8948#define DUK_ASC_UC_A 0x41
8949#define DUK_ASC_UC_B 0x42
8950#define DUK_ASC_UC_C 0x43
8951#define DUK_ASC_UC_D 0x44
8952#define DUK_ASC_UC_E 0x45
8953#define DUK_ASC_UC_F 0x46
8954#define DUK_ASC_UC_G 0x47
8955#define DUK_ASC_UC_H 0x48
8956#define DUK_ASC_UC_I 0x49
8957#define DUK_ASC_UC_J 0x4a
8958#define DUK_ASC_UC_K 0x4b
8959#define DUK_ASC_UC_L 0x4c
8960#define DUK_ASC_UC_M 0x4d
8961#define DUK_ASC_UC_N 0x4e
8962#define DUK_ASC_UC_O 0x4f
8963#define DUK_ASC_UC_P 0x50
8964#define DUK_ASC_UC_Q 0x51
8965#define DUK_ASC_UC_R 0x52
8966#define DUK_ASC_UC_S 0x53
8967#define DUK_ASC_UC_T 0x54
8968#define DUK_ASC_UC_U 0x55
8969#define DUK_ASC_UC_V 0x56
8970#define DUK_ASC_UC_W 0x57
8971#define DUK_ASC_UC_X 0x58
8972#define DUK_ASC_UC_Y 0x59
8973#define DUK_ASC_UC_Z 0x5a
8974#define DUK_ASC_LBRACKET 0x5b
8975#define DUK_ASC_BACKSLASH 0x5c
8976#define DUK_ASC_RBRACKET 0x5d
8977#define DUK_ASC_CARET 0x5e
8978#define DUK_ASC_UNDERSCORE 0x5f
8979#define DUK_ASC_GRAVE 0x60
8980#define DUK_ASC_LC_A 0x61
8981#define DUK_ASC_LC_B 0x62
8982#define DUK_ASC_LC_C 0x63
8983#define DUK_ASC_LC_D 0x64
8984#define DUK_ASC_LC_E 0x65
8985#define DUK_ASC_LC_F 0x66
8986#define DUK_ASC_LC_G 0x67
8987#define DUK_ASC_LC_H 0x68
8988#define DUK_ASC_LC_I 0x69
8989#define DUK_ASC_LC_J 0x6a
8990#define DUK_ASC_LC_K 0x6b
8991#define DUK_ASC_LC_L 0x6c
8992#define DUK_ASC_LC_M 0x6d
8993#define DUK_ASC_LC_N 0x6e
8994#define DUK_ASC_LC_O 0x6f
8995#define DUK_ASC_LC_P 0x70
8996#define DUK_ASC_LC_Q 0x71
8997#define DUK_ASC_LC_R 0x72
8998#define DUK_ASC_LC_S 0x73
8999#define DUK_ASC_LC_T 0x74
9000#define DUK_ASC_LC_U 0x75
9001#define DUK_ASC_LC_V 0x76
9002#define DUK_ASC_LC_W 0x77
9003#define DUK_ASC_LC_X 0x78
9004#define DUK_ASC_LC_Y 0x79
9005#define DUK_ASC_LC_Z 0x7a
9006#define DUK_ASC_LCURLY 0x7b
9007#define DUK_ASC_PIPE 0x7c
9008#define DUK_ASC_RCURLY 0x7d
9009#define DUK_ASC_TILDE 0x7e
9010#define DUK_ASC_DEL 0x7f
9011
9012/*
9013 * Miscellaneous
9014 */
9015
9016/* Uppercase A is 0x41, lowercase a is 0x61; OR 0x20 to convert uppercase
9017 * to lowercase.
9018 */
9019#define DUK_LOWERCASE_CHAR_ASCII(x) ((x) | 0x20)
9020
9021/*
9022 * Unicode tables
9023 */
9024
9025#if defined(DUK_USE_SOURCE_NONBMP)
9026/*
9027 * Automatically generated by extract_chars.py, do not edit!
9028 */
9029
9030extern const duk_uint8_t duk_unicode_ids_noa[1036];
9031#else
9032/*
9033 * Automatically generated by extract_chars.py, do not edit!
9034 */
9035
9036extern const duk_uint8_t duk_unicode_ids_noabmp[625];
9037#endif
9038
9039#if defined(DUK_USE_SOURCE_NONBMP)
9040/*
9041 * Automatically generated by extract_chars.py, do not edit!
9042 */
9043
9044extern const duk_uint8_t duk_unicode_ids_m_let_noa[42];
9045#else
9046/*
9047 * Automatically generated by extract_chars.py, do not edit!
9048 */
9049
9050extern const duk_uint8_t duk_unicode_ids_m_let_noabmp[24];
9051#endif
9052
9053#if defined(DUK_USE_SOURCE_NONBMP)
9054/*
9055 * Automatically generated by extract_chars.py, do not edit!
9056 */
9057
9058extern const duk_uint8_t duk_unicode_idp_m_ids_noa[530];
9059#else
9060/*
9061 * Automatically generated by extract_chars.py, do not edit!
9062 */
9063
9064extern const duk_uint8_t duk_unicode_idp_m_ids_noabmp[357];
9065#endif
9066
9067/*
9068 * Automatically generated by extract_caseconv.py, do not edit!
9069 */
9070
9071extern const duk_uint8_t duk_unicode_caseconv_uc[1386];
9072extern const duk_uint8_t duk_unicode_caseconv_lc[680];
9073
9074#if defined(DUK_USE_REGEXP_CANON_WORKAROUND)
9075/*
9076 * Automatically generated by extract_caseconv.py, do not edit!
9077 */
9078
9079extern const duk_uint16_t duk_unicode_re_canon_lookup[65536];
9080#endif
9081
9082/*
9083 * Extern
9084 */
9085
9086/* duk_unicode_support.c */
9087#if !defined(DUK_SINGLE_FILE)
9088DUK_INTERNAL_DECL const duk_uint8_t duk_unicode_xutf8_markers[7];
9089DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_digit[2];
9090DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_white[22];
9091DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_wordchar[8];
9092DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_not_digit[4];
9093DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_not_white[24];
9094DUK_INTERNAL_DECL const duk_uint16_t duk_unicode_re_ranges_not_wordchar[10];
9095DUK_INTERNAL_DECL const duk_int8_t duk_is_idchar_tab[128];
9096#endif /* !DUK_SINGLE_FILE */
9097
9098/*
9099 * Prototypes
9100 */
9101
9102DUK_INTERNAL_DECL duk_small_int_t duk_unicode_get_xutf8_length(duk_ucodepoint_t cp);
9103#if defined(DUK_USE_ASSERTIONS)
9104DUK_INTERNAL_DECL duk_small_int_t duk_unicode_get_cesu8_length(duk_ucodepoint_t cp);
9105#endif
9106DUK_INTERNAL_DECL duk_small_int_t duk_unicode_encode_xutf8(duk_ucodepoint_t cp, duk_uint8_t *out);
9107DUK_INTERNAL_DECL duk_small_int_t duk_unicode_encode_cesu8(duk_ucodepoint_t cp, duk_uint8_t *out);
9108DUK_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);
9109DUK_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);
9110DUK_INTERNAL_DECL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen);
9111DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_whitespace(duk_codepoint_t cp);
9112DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_line_terminator(duk_codepoint_t cp);
9113DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_t cp);
9114DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp);
9115DUK_INTERNAL_DECL duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp);
9116DUK_INTERNAL_DECL void duk_unicode_case_convert_string(duk_hthread *thr, duk_bool_t uppercase);
9117#if defined(DUK_USE_REGEXP_SUPPORT)
9118DUK_INTERNAL_DECL duk_codepoint_t duk_unicode_re_canonicalize_char(duk_hthread *thr, duk_codepoint_t cp);
9119DUK_INTERNAL_DECL duk_small_int_t duk_unicode_re_is_wordchar(duk_codepoint_t cp);
9120#endif
9121
9122#endif /* DUK_UNICODE_H_INCLUDED */
9123/* #include duk_json.h */
9124/*
9125 * Defines for JSON, especially duk_bi_json.c.
9126 */
9127
9128#if !defined(DUK_JSON_H_INCLUDED)
9129#define DUK_JSON_H_INCLUDED
9131/* Encoding/decoding flags */
9132#define DUK_JSON_FLAG_ASCII_ONLY (1 << 0) /* escape any non-ASCII characters */
9133#define DUK_JSON_FLAG_AVOID_KEY_QUOTES (1 << 1) /* avoid key quotes when key is an ASCII Identifier */
9134#define DUK_JSON_FLAG_EXT_CUSTOM (1 << 2) /* extended types: custom encoding */
9135#define DUK_JSON_FLAG_EXT_COMPATIBLE (1 << 3) /* extended types: compatible encoding */
9136
9137/* How much stack to require on entry to object/array encode */
9138#define DUK_JSON_ENC_REQSTACK 32
9139
9140/* How much stack to require on entry to object/array decode */
9141#define DUK_JSON_DEC_REQSTACK 32
9142
9143/* How large a loop detection stack to use */
9144#define DUK_JSON_ENC_LOOPARRAY 64
9145
9146/* Encoding state. Heap object references are all borrowed. */
9147typedef struct {
9148 duk_hthread *thr;
9149 duk_bufwriter_ctx bw; /* output bufwriter */
9150 duk_hobject *h_replacer; /* replacer function */
9151 duk_hstring *h_gap; /* gap (if empty string, NULL) */
9152 duk_idx_t idx_proplist; /* explicit PropertyList */
9153 duk_idx_t idx_loop; /* valstack index of loop detection object */
9154 duk_small_uint_t flags;
9155 duk_small_uint_t flag_ascii_only;
9156 duk_small_uint_t flag_avoid_key_quotes;
9157#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
9158 duk_small_uint_t flag_ext_custom;
9159 duk_small_uint_t flag_ext_compatible;
9160 duk_small_uint_t flag_ext_custom_or_compatible;
9161#endif
9162 duk_int_t recursion_depth;
9163 duk_int_t recursion_limit;
9164 duk_uint_t mask_for_undefined; /* type bit mask: types which certainly produce 'undefined' */
9165#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
9166 duk_small_uint_t stridx_custom_undefined;
9167 duk_small_uint_t stridx_custom_nan;
9168 duk_small_uint_t stridx_custom_neginf;
9169 duk_small_uint_t stridx_custom_posinf;
9170 duk_small_uint_t stridx_custom_function;
9171#endif
9172 duk_hobject *visiting[DUK_JSON_ENC_LOOPARRAY]; /* indexed by recursion_depth */
9174
9175typedef struct {
9176 duk_hthread *thr;
9177 const duk_uint8_t *p;
9178 const duk_uint8_t *p_start;
9179 const duk_uint8_t *p_end;
9180 duk_idx_t idx_reviver;
9181 duk_small_uint_t flags;
9182#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
9183 duk_small_uint_t flag_ext_custom;
9184 duk_small_uint_t flag_ext_compatible;
9185 duk_small_uint_t flag_ext_custom_or_compatible;
9186#endif
9187 duk_int_t recursion_depth;
9188 duk_int_t recursion_limit;
9190
9191#endif /* DUK_JSON_H_INCLUDED */
9192/* #include duk_js.h */
9193/*
9194 * Ecmascript execution, support primitives.
9195 */
9196
9197#if !defined(DUK_JS_H_INCLUDED)
9198#define DUK_JS_H_INCLUDED
9199
9200/* Flags for call handling. */
9201#define DUK_CALL_FLAG_IGNORE_RECLIMIT (1 << 0) /* duk_handle_call_xxx: call ignores C recursion limit (for errhandler calls) */
9202#define DUK_CALL_FLAG_CONSTRUCTOR_CALL (1 << 1) /* duk_handle_call_xxx: constructor call (i.e. called as 'new Foo()') */
9203#define DUK_CALL_FLAG_IS_RESUME (1 << 2) /* duk_handle_ecma_call_setup: setup for a resume() */
9204#define DUK_CALL_FLAG_IS_TAILCALL (1 << 3) /* duk_handle_ecma_call_setup: setup for a tail call */
9205#define DUK_CALL_FLAG_DIRECT_EVAL (1 << 4) /* call is a direct eval call */
9206
9207/* Flags for duk_js_equals_helper(). */
9208#define DUK_EQUALS_FLAG_SAMEVALUE (1 << 0) /* use SameValue instead of non-strict equality */
9209#define DUK_EQUALS_FLAG_STRICT (1 << 1) /* use strict equality instead of non-strict equality */
9210
9211/* Flags for duk_js_compare_helper(). */
9212#define DUK_COMPARE_FLAG_NEGATE (1 << 0) /* negate result */
9213#define DUK_COMPARE_FLAG_EVAL_LEFT_FIRST (1 << 1) /* eval left argument first */
9214
9215/* conversions, coercions, comparison, etc */
9216DUK_INTERNAL_DECL duk_bool_t duk_js_toboolean(duk_tval *tv);
9217DUK_INTERNAL_DECL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv);
9218DUK_INTERNAL_DECL duk_double_t duk_js_tointeger_number(duk_double_t x);
9219DUK_INTERNAL_DECL duk_double_t duk_js_tointeger(duk_hthread *thr, duk_tval *tv);
9220DUK_INTERNAL_DECL duk_uint32_t duk_js_touint32(duk_hthread *thr, duk_tval *tv);
9221DUK_INTERNAL_DECL duk_int32_t duk_js_toint32(duk_hthread *thr, duk_tval *tv);
9222DUK_INTERNAL_DECL duk_uint16_t duk_js_touint16(duk_hthread *thr, duk_tval *tv);
9223DUK_INTERNAL_DECL duk_small_int_t duk_js_to_arrayindex_raw_string(const duk_uint8_t *str, duk_uint32_t blen, duk_uarridx_t *out_idx);
9224DUK_INTERNAL_DECL duk_uarridx_t duk_js_to_arrayindex_string_helper(duk_hstring *h);
9225DUK_INTERNAL_DECL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags);
9226DUK_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);
9227DUK_INTERNAL_DECL duk_small_int_t duk_js_string_compare(duk_hstring *h1, duk_hstring *h2);
9228#if 0 /* unused */
9229DUK_INTERNAL_DECL duk_small_int_t duk_js_buffer_compare(duk_heap *heap, duk_hbuffer *h1, duk_hbuffer *h2);
9230#endif
9231DUK_INTERNAL_DECL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags);
9232DUK_INTERNAL_DECL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
9233DUK_INTERNAL_DECL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y);
9234DUK_INTERNAL_DECL duk_small_uint_t duk_js_typeof_stridx(duk_tval *tv_x);
9235
9236/* arithmetic */
9237DUK_INTERNAL_DECL double duk_js_arith_pow(double x, double y);
9238DUK_INTERNAL_DECL double duk_js_arith_mod(double x, double y);
9239
9240#define duk_js_equals(thr,tv_x,tv_y) \
9241 duk_js_equals_helper((thr), (tv_x), (tv_y), 0)
9242#define duk_js_strict_equals(tv_x,tv_y) \
9243 duk_js_equals_helper(NULL, (tv_x), (tv_y), DUK_EQUALS_FLAG_STRICT)
9244#define duk_js_samevalue(tv_x,tv_y) \
9245 duk_js_equals_helper(NULL, (tv_x), (tv_y), DUK_EQUALS_FLAG_SAMEVALUE)
9246
9247/* E5 Sections 11.8.1, 11.8.5; x < y */
9248#define duk_js_lessthan(thr,tv_x,tv_y) \
9249 duk_js_compare_helper((thr), (tv_x), (tv_Y), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST)
9250
9251/* E5 Sections 11.8.2, 11.8.5; x > y --> y < x */
9252#define duk_js_greaterthan(thr,tv_x,tv_y) \
9253 duk_js_compare_helper((thr), (tv_y), (tv_x), 0)
9254
9255/* E5 Sections 11.8.3, 11.8.5; x <= y --> not (x > y) --> not (y < x) */
9256#define duk_js_lessthanorequal(thr,tv_x,tv_y) \
9257 duk_js_compare_helper((thr), (tv_y), (tv_x), DUK_COMPARE_FLAG_NEGATE)
9258
9259/* E5 Sections 11.8.4, 11.8.5; x >= y --> not (x < y) */
9260#define duk_js_greaterthanorequal(thr,tv_x,tv_y) \
9261 duk_js_compare_helper((thr), (tv_x), (tv_y), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST | DUK_COMPARE_FLAG_NEGATE)
9262
9263/* identifiers and environment handling */
9264#if 0 /*unused*/
9265DUK_INTERNAL duk_bool_t duk_js_hasvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name);
9266#endif
9267DUK_INTERNAL_DECL duk_bool_t duk_js_getvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name, duk_bool_t throw_flag);
9268DUK_INTERNAL_DECL duk_bool_t duk_js_getvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_bool_t throw_flag);
9269DUK_INTERNAL_DECL void duk_js_putvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name, duk_tval *val, duk_bool_t strict);
9270DUK_INTERNAL_DECL void duk_js_putvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_bool_t strict);
9271#if 0 /*unused*/
9272DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_envrec(duk_hthread *thr, duk_hobject *env, duk_hstring *name);
9273#endif
9274DUK_INTERNAL_DECL duk_bool_t duk_js_delvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name);
9275DUK_INTERNAL_DECL duk_bool_t duk_js_declvar_activation(duk_hthread *thr, duk_activation *act, duk_hstring *name, duk_tval *val, duk_small_int_t prop_flags, duk_bool_t is_func_decl);
9276DUK_INTERNAL_DECL void duk_js_init_activation_environment_records_delayed(duk_hthread *thr, duk_activation *act);
9277DUK_INTERNAL_DECL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env, duk_hobject *func, duk_size_t regbase);
9278DUK_INTERNAL_DECL duk_hobject *duk_create_activation_environment_record(duk_hthread *thr, duk_hobject *func, duk_size_t idx_bottom);
9279DUK_INTERNAL_DECL
9280void duk_js_push_closure(duk_hthread *thr,
9281 duk_hcompfunc *fun_temp,
9282 duk_hobject *outer_var_env,
9283 duk_hobject *outer_lex_env,
9284 duk_bool_t add_auto_proto);
9285
9286/* call handling */
9287DUK_INTERNAL_DECL duk_int_t duk_handle_call_protected(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
9288DUK_INTERNAL_DECL void duk_handle_call_unprotected(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
9289DUK_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);
9290DUK_INTERNAL_DECL duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr, duk_idx_t num_stack_args, duk_small_uint_t call_flags);
9291
9292/* bytecode execution */
9293DUK_INTERNAL_DECL void duk_js_execute_bytecode(duk_hthread *exec_thr);
9294
9295#endif /* DUK_JS_H_INCLUDED */
9296/* #include duk_numconv.h */
9297/*
9298 * Number-to-string conversion. The semantics of these is very tightly
9299 * bound with the Ecmascript semantics required for call sites.
9300 */
9301
9302#if !defined(DUK_NUMCONV_H_INCLUDED)
9303#define DUK_NUMCONV_H_INCLUDED
9304
9305/* Output a specified number of digits instead of using the shortest
9306 * form. Used for toPrecision() and toFixed().
9307 */
9308#define DUK_N2S_FLAG_FIXED_FORMAT (1 << 0)
9309
9310/* Force exponential format. Used for toExponential(). */
9311#define DUK_N2S_FLAG_FORCE_EXP (1 << 1)
9312
9313/* If number would need zero padding (for whole number part), use
9314 * exponential format instead. E.g. if input number is 12300, 3
9315 * digits are generated ("123"), output "1.23e+4" instead of "12300".
9316 * Used for toPrecision().
9317 */
9318#define DUK_N2S_FLAG_NO_ZERO_PAD (1 << 2)
9319
9320/* Digit count indicates number of fractions (i.e. an absolute
9321 * digit index instead of a relative one). Used together with
9322 * DUK_N2S_FLAG_FIXED_FORMAT for toFixed().
9323 */
9324#define DUK_N2S_FLAG_FRACTION_DIGITS (1 << 3)
9325
9326/*
9327 * String-to-number conversion
9328 */
9329
9330/* Maximum exponent value when parsing numbers. This is not strictly
9331 * compliant as there should be no upper limit, but as we parse the
9332 * exponent without a bigint, impose some limit.
9333 */
9334#define DUK_S2N_MAX_EXPONENT 1000000000
9335
9336/* Trim white space (= allow leading and trailing whitespace) */
9337#define DUK_S2N_FLAG_TRIM_WHITE (1 << 0)
9338
9339/* Allow exponent */
9340#define DUK_S2N_FLAG_ALLOW_EXP (1 << 1)
9341
9342/* Allow trailing garbage (e.g. treat "123foo" as "123) */
9343#define DUK_S2N_FLAG_ALLOW_GARBAGE (1 << 2)
9344
9345/* Allow leading plus sign */
9346#define DUK_S2N_FLAG_ALLOW_PLUS (1 << 3)
9347
9348/* Allow leading minus sign */
9349#define DUK_S2N_FLAG_ALLOW_MINUS (1 << 4)
9350
9351/* Allow 'Infinity' */
9352#define DUK_S2N_FLAG_ALLOW_INF (1 << 5)
9353
9354/* Allow fraction part */
9355#define DUK_S2N_FLAG_ALLOW_FRAC (1 << 6)
9356
9357/* Allow naked fraction (e.g. ".123") */
9358#define DUK_S2N_FLAG_ALLOW_NAKED_FRAC (1 << 7)
9359
9360/* Allow empty fraction (e.g. "123.") */
9361#define DUK_S2N_FLAG_ALLOW_EMPTY_FRAC (1 << 8)
9362
9363/* Allow empty string to be interpreted as 0 */
9364#define DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO (1 << 9)
9365
9366/* Allow leading zeroes (e.g. "0123" -> "123") */
9367#define DUK_S2N_FLAG_ALLOW_LEADING_ZERO (1 << 10)
9368
9369/* Allow automatic detection of hex base ("0x" or "0X" prefix),
9370 * overrides radix argument and forces integer mode.
9371 */
9372#define DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT (1 << 11)
9373
9374/* Allow automatic detection of legacy octal base ("0n"),
9375 * overrides radix argument and forces integer mode.
9376 */
9377#define DUK_S2N_FLAG_ALLOW_AUTO_LEGACY_OCT_INT (1 << 12)
9378
9379/* Allow automatic detection of ES2015 octal base ("0o123"),
9380 * overrides radix argument and forces integer mode.
9381 */
9382#define DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT (1 << 13)
9383
9384/* Allow automatic detection of ES2015 binary base ("0b10001"),
9385 * overrides radix argument and forces integer mode.
9386 */
9387#define DUK_S2N_FLAG_ALLOW_AUTO_BIN_INT (1 << 14)
9388
9389/*
9390 * Prototypes
9391 */
9392
9393DUK_INTERNAL_DECL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags);
9394DUK_INTERNAL_DECL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk_small_uint_t flags);
9395
9396#endif /* DUK_NUMCONV_H_INCLUDED */
9397/* #include duk_bi_protos.h */
9398/*
9399 * Prototypes for built-in functions not automatically covered by the
9400 * header declarations emitted by genbuiltins.py.
9401 */
9402
9403#if !defined(DUK_BUILTIN_PROTOS_H_INCLUDED)
9404#define DUK_BUILTIN_PROTOS_H_INCLUDED
9405
9406/* Buffer size needed for ISO 8601 formatting.
9407 * Accurate value is 32 + 1 for NUL termination:
9408 * >>> len('+123456-01-23T12:34:56.123+12:34')
9409 * 32
9410 * Include additional space to be safe.
9411 */
9412#define DUK_BI_DATE_ISO8601_BUFSIZE 40
9413
9414/* Helpers exposed for internal use */
9415DUK_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);
9416DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t *dparts, duk_small_uint_t flags);
9417DUK_INTERNAL_DECL duk_bool_t duk_bi_date_is_leap_year(duk_int_t year);
9418DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_valid_range(duk_double_t x);
9419DUK_INTERNAL_DECL duk_bool_t duk_bi_date_year_in_valid_range(duk_double_t year);
9420DUK_INTERNAL_DECL duk_bool_t duk_bi_date_timeval_in_leeway_range(duk_double_t x);
9421/* Built-in providers */
9422#if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY)
9423DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_gettimeofday(duk_context *ctx);
9424#endif
9425#if defined(DUK_USE_DATE_NOW_TIME)
9426DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_time(duk_context *ctx);
9427#endif
9428#if defined(DUK_USE_DATE_NOW_WINDOWS)
9429DUK_INTERNAL_DECL duk_double_t duk_bi_date_get_now_windows(duk_context *ctx);
9430#endif
9431#if defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S) || defined(DUK_USE_DATE_TZO_GMTIME)
9432DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d);
9433#endif
9434#if defined(DUK_USE_DATE_TZO_WINDOWS)
9435DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d);
9436#endif
9437#if defined(DUK_USE_DATE_PRS_STRPTIME)
9438DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_strptime(duk_context *ctx, const char *str);
9439#endif
9440#if defined(DUK_USE_DATE_PRS_GETDATE)
9441DUK_INTERNAL_DECL duk_bool_t duk_bi_date_parse_string_getdate(duk_context *ctx, const char *str);
9442#endif
9443#if defined(DUK_USE_DATE_FMT_STRFTIME)
9444DUK_INTERNAL_DECL duk_bool_t duk_bi_date_format_parts_strftime(duk_context *ctx, duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags);
9445#endif
9446
9447DUK_INTERNAL_DECL
9448void duk_bi_json_parse_helper(duk_context *ctx,
9449 duk_idx_t idx_value,
9450 duk_idx_t idx_reviver,
9451 duk_small_uint_t flags);
9452DUK_INTERNAL_DECL
9453void duk_bi_json_stringify_helper(duk_context *ctx,
9454 duk_idx_t idx_value,
9455 duk_idx_t idx_replacer,
9456 duk_idx_t idx_space,
9457 duk_small_uint_t flags);
9458
9459DUK_INTERNAL_DECL duk_ret_t duk_textdecoder_decode_utf8_nodejs(duk_context *ctx);
9460
9461#if defined(DUK_USE_ES6_PROXY)
9462DUK_INTERNAL_DECL void duk_proxy_ownkeys_postprocess(duk_context *ctx, duk_hobject *h_proxy_target, duk_uint_t flags);
9463#endif
9464
9465#endif /* DUK_BUILTIN_PROTOS_H_INCLUDED */
9466/* #include duk_selftest.h */
9467/*
9468 * Selftest code
9469 */
9470
9471#if !defined(DUK_SELFTEST_H_INCLUDED)
9472#define DUK_SELFTEST_H_INCLUDED
9473
9474#if defined(DUK_USE_SELF_TESTS)
9475DUK_INTERNAL_DECL duk_uint_t duk_selftest_run_tests(duk_alloc_function alloc_func,
9476 duk_realloc_function realloc_func,
9477 duk_free_function free_func,
9478 void *udata);
9479#endif
9480
9481#endif /* DUK_SELFTEST_H_INCLUDED */
9482
9483#endif /* DUK_INTERNAL_H_INCLUDED */
9484
9485#if defined(DUK_USE_COMPUTED_NAN)
9486DUK_INTERNAL double duk_computed_nan;
9487#endif
9488
9489#if defined(DUK_USE_COMPUTED_INFINITY)
9490DUK_INTERNAL double duk_computed_infinity;
9491#endif
9492
9493#if defined(DUK_USE_REPL_FPCLASSIFY)
9494DUK_INTERNAL int duk_repl_fpclassify(double x) {
9496 duk_uint_fast16_t expt;
9497 duk_small_int_t mzero;
9498
9499 u.d = x;
9500 expt = (duk_uint_fast16_t) (u.us[DUK_DBL_IDX_US0] & 0x7ff0UL);
9501 if (expt > 0x0000UL && expt < 0x7ff0UL) {
9502 /* expt values [0x001,0x7fe] = normal */
9503 return DUK_FP_NORMAL;
9504 }
9505
9506 mzero = (u.ui[DUK_DBL_IDX_UI1] == 0 && (u.ui[DUK_DBL_IDX_UI0] & 0x000fffffUL) == 0);
9507 if (expt == 0x0000UL) {
9508 /* expt 0x000 is zero/subnormal */
9509 if (mzero) {
9510 return DUK_FP_ZERO;
9511 } else {
9512 return DUK_FP_SUBNORMAL;
9513 }
9514 } else {
9515 /* expt 0xfff is infinite/nan */
9516 if (mzero) {
9517 return DUK_FP_INFINITE;
9518 } else {
9519 return DUK_FP_NAN;
9520 }
9521 }
9522}
9523#endif
9524
9525#if defined(DUK_USE_REPL_SIGNBIT)
9526DUK_INTERNAL int duk_repl_signbit(double x) {
9528 u.d = x;
9529 return (int) (u.uc[DUK_DBL_IDX_UC0] & 0x80UL);
9530}
9531#endif
9532
9533#if defined(DUK_USE_REPL_ISFINITE)
9534DUK_INTERNAL int duk_repl_isfinite(double x) {
9535 int c = DUK_FPCLASSIFY(x);
9536 if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
9537 return 0;
9538 } else {
9539 return 1;
9540 }
9541}
9542#endif
9543
9544#if defined(DUK_USE_REPL_ISNAN)
9545DUK_INTERNAL int duk_repl_isnan(double x) {
9546 int c = DUK_FPCLASSIFY(x);
9547 return (c == DUK_FP_NAN);
9548}
9549#endif
9550
9551#if defined(DUK_USE_REPL_ISINF)
9552DUK_INTERNAL int duk_repl_isinf(double x) {
9553 int c = DUK_FPCLASSIFY(x);
9554 return (c == DUK_FP_INFINITE);
9555}
9556#endif
9557/*
9558 * Debugging macro calls.
9559 */
9560
9561/* #include duk_internal.h -> already included */
9562
9563#if defined(DUK_USE_DEBUG)
9564
9565/*
9566 * Debugging enabled
9567 */
9568
9569#include <stdio.h>
9570#include <stdlib.h>
9571#include <stdarg.h>
9572
9573#if !defined(DUK_USE_DEBUG_WRITE)
9574#error debugging enabled (DUK_USE_DEBUG) but DUK_USE_DEBUG_WRITE not defined
9575#endif
9576
9577#define DUK__DEBUG_BUFSIZE DUK_USE_DEBUG_BUFSIZE
9578
9579#if defined(DUK_USE_VARIADIC_MACROS)
9580
9581DUK_INTERNAL void duk_debug_log(duk_int_t level, const char *file, duk_int_t line, const char *func, const char *fmt, ...) {
9582 va_list ap;
9583 long arg_level;
9584 const char *arg_file;
9585 long arg_line;
9586 const char *arg_func;
9587 const char *arg_msg;
9588 char buf[DUK__DEBUG_BUFSIZE];
9589
9590 va_start(ap, fmt);
9591
9592 DUK_MEMZERO((void *) buf, (size_t) DUK__DEBUG_BUFSIZE);
9593 duk_debug_vsnprintf(buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
9594
9595 arg_level = (long) level;
9596 arg_file = (const char *) file;
9597 arg_line = (long) line;
9598 arg_func = (const char *) func;
9599 arg_msg = (const char *) buf;
9600 DUK_USE_DEBUG_WRITE(arg_level, arg_file, arg_line, arg_func, arg_msg);
9601
9602 va_end(ap);
9603}
9604
9605#else /* DUK_USE_VARIADIC_MACROS */
9606
9607DUK_INTERNAL char duk_debug_file_stash[DUK_DEBUG_STASH_SIZE];
9608DUK_INTERNAL duk_int_t duk_debug_line_stash;
9609DUK_INTERNAL char duk_debug_func_stash[DUK_DEBUG_STASH_SIZE];
9610DUK_INTERNAL duk_int_t duk_debug_level_stash;
9611
9612DUK_INTERNAL void duk_debug_log(const char *fmt, ...) {
9613 va_list ap;
9614 long arg_level;
9615 const char *arg_file;
9616 long arg_line;
9617 const char *arg_func;
9618 const char *arg_msg;
9619 char buf[DUK__DEBUG_BUFSIZE];
9620
9621 va_start(ap, fmt);
9622
9623 DUK_MEMZERO((void *) buf, (size_t) DUK__DEBUG_BUFSIZE);
9624 duk_debug_vsnprintf(buf, DUK__DEBUG_BUFSIZE - 1, fmt, ap);
9625
9626 arg_level = (long) duk_debug_level_stash;
9627 arg_file = (const char *) duk_debug_file_stash;
9628 arg_line = (long) duk_debug_line_stash;
9629 arg_func = (const char *) duk_debug_func_stash;
9630 arg_msg = (const char *) buf;
9631 DUK_USE_DEBUG_WRITE(arg_level, arg_file, arg_line, arg_func, arg_msg);
9632
9633 va_end(ap);
9634}
9635
9636#endif /* DUK_USE_VARIADIC_MACROS */
9637
9638#else /* DUK_USE_DEBUG */
9639
9640/*
9641 * Debugging disabled
9642 */
9643
9644#endif /* DUK_USE_DEBUG */
9645
9646/* automatic undefs */
9647#undef DUK__DEBUG_BUFSIZE
9648/*
9649 * Automatically generated by genbuiltins.py, do not edit!
9650 */
9651
9652/* #include duk_internal.h -> already included */
9653
9654#if defined(DUK_USE_ROM_STRINGS)
9655#error ROM support not enabled, rerun configure.py with --rom-support
9656#else /* DUK_USE_ROM_STRINGS */
9657DUK_INTERNAL const duk_uint8_t duk_strings_data[921] = {
965879,40,209,144,168,105,6,78,54,139,89,185,44,48,46,90,120,8,154,140,35,103,
965935,113,193,73,5,52,112,180,104,166,135,52,188,4,98,12,27,146,156,80,211,31,
9660129,115,150,64,52,220,109,24,18,68,156,24,38,67,114,36,55,9,119,151,132,
9661140,93,18,113,128,153,201,212,201,205,2,248,8,196,24,224,104,82,146,40,224,
9662193,48,114,168,37,147,196,54,123,28,4,98,12,43,148,67,103,177,192,70,32,
9663196,121,68,54,123,28,18,192,199,144,124,4,98,12,43,136,108,244,117,184,8,
9664196,24,95,40,134,207,71,91,128,140,65,133,113,13,158,158,151,1,24,131,11,
9665229,16,217,233,233,112,17,136,48,206,21,110,4,244,244,184,8,196,24,103,10,
9666183,2,122,218,156,4,98,12,24,203,112,64,179,113,193,79,8,218,155,131,32,
9667184,70,212,220,13,10,82,68,252,123,144,217,146,38,228,207,18,0,100,37,64,
9668178,212,11,161,17,104,162,96,10,200,193,57,165,65,169,16,5,100,81,27,70,18,
966932,10,200,68,185,13,116,221,197,184,64,89,57,41,197,13,49,234,5,208,156,
9670113,87,55,118,147,20,187,56,161,166,92,221,212,73,210,236,226,134,153,115,
9671119,76,201,203,179,138,26,99,73,212,136,136,164,25,174,137,56,32,72,137,
9672101,23,52,45,13,34,86,9,79,136,104,201,114,149,96,52,138,134,140,151,75,
9673226,233,186,120,121,22,39,54,83,141,5,55,68,236,36,164,3,16,225,115,150,64,
967452,205,163,2,72,154,83,138,26,99,75,12,11,150,103,5,36,20,211,70,140,133,
967567,72,49,241,160,227,81,196,52,168,106,39,132,252,183,136,105,80,212,79,2,
9676249,110,128,126,88,95,133,109,237,237,237,151,235,127,46,249,119,203,190,
9677186,206,33,181,2,208,61,190,12,19,34,65,19,81,132,108,228,97,1,107,33,12,
967832,45,100,139,134,69,146,100,227,226,231,146,51,192,204,73,140,224,145,221,
9679102,241,68,196,157,34,79,143,139,166,233,225,228,227,138,157,173,167,197,
9680211,118,214,210,38,238,74,113,67,76,105,187,169,147,154,73,225,228,32,193,
968148,25,100,105,166,113,200,147,44,166,1,40,79,18,150,134,147,141,163,2,72,
9682171,115,147,136,4,65,130,96,35,64,194,32,168,89,56,208,48,135,123,144,217,
9683146,38,220,229,64,186,16,187,156,105,47,52,238,112,56,153,4,225,145,27,156,
968443,162,192,46,71,220,229,65,22,1,231,220,228,157,72,136,136,220,227,197,
9685164,180,52,133,220,224,34,105,19,115,140,3,207,185,202,130,36,109,85,185,
9686194,161,160,90,50,72,163,115,135,3,70,178,68,251,156,16,22,178,16,251,156,
9687153,226,64,13,27,156,137,12,16,72,135,220,228,193,19,18,101,220,228,206,
9688137,28,78,99,208,178,21,13,125,38,146,70,60,20,72,9,145,4,140,121,51,197,
9689214,25,27,81,156,151,48,65,34,107,106,9,55,18,68,104,146,84,97,31,191,189,
9690181,70,140,133,222,249,212,227,66,125,245,187,251,219,77,3,119,190,117,56,
9691208,159,125,110,254,246,210,26,93,239,157,78,52,39,223,93,191,189,180,212,
969252,187,223,58,156,104,79,190,187,127,123,104,180,104,183,190,117,56,208,
9693159,125,102,254,209,104,209,124,234,113,161,62,250,80,196,128,81,4,9,16,
9694162,4,196,116,9,205,154,27,66,32,100,13,12,98,68,227,33,65,69,204,195,34,
9695201,50,8,110,33,23,34,28,168,104,22,188,12,174,138,11,70,138,104,115,68,
9696130,137,13,82,27,41,129,162,35,138,54,146,198,137,39,72,180,210,178,38,35,
9697146,103,68,139,51,197,214,28,227,131,79,15,35,138,58,130,37,19,155,41,146,
9698174,64,203,99,161,100,37,145,51,148,75,4,164,66,54,140,49,46,247,70,103,37,
9699230,70,142,70,67,30,232,204,178,163,201,18,54,139,89,39,26,16,165,2,228,69,
970033,143,89,24,70,206,73,67,102,72,148,2,32,214,73,157,224,18,128,98,29,241,
970169,65,50,37,241,116,200,41,144,102,125,2,180,8,210,152,38,129,23,8,34,198,
9702};
9703#endif /* DUK_USE_ROM_STRINGS */
9704
9705#if defined(DUK_USE_ROM_OBJECTS)
9706#error ROM support not enabled, rerun configure.py with --rom-support
9707#else /* DUK_USE_ROM_OBJECTS */
9708/* native functions: 164 */
9709DUK_INTERNAL const duk_c_function duk_bi_native_functions[164] = {
9710 NULL,
9711 duk_bi_array_constructor,
9712 duk_bi_array_constructor_is_array,
9713 duk_bi_array_prototype_concat,
9714 duk_bi_array_prototype_indexof_shared,
9715 duk_bi_array_prototype_iter_shared,
9716 duk_bi_array_prototype_join_shared,
9717 duk_bi_array_prototype_pop,
9718 duk_bi_array_prototype_push,
9719 duk_bi_array_prototype_reduce_shared,
9720 duk_bi_array_prototype_reverse,
9721 duk_bi_array_prototype_shift,
9722 duk_bi_array_prototype_slice,
9723 duk_bi_array_prototype_sort,
9724 duk_bi_array_prototype_splice,
9725 duk_bi_array_prototype_to_string,
9726 duk_bi_array_prototype_unshift,
9727 duk_bi_arraybuffer_constructor,
9728 duk_bi_arraybuffer_isview,
9729 duk_bi_boolean_constructor,
9730 duk_bi_boolean_prototype_tostring_shared,
9731 duk_bi_buffer_compare_shared,
9732 duk_bi_buffer_readfield,
9733 duk_bi_buffer_slice_shared,
9734 duk_bi_buffer_writefield,
9735 duk_bi_dataview_constructor,
9736 duk_bi_date_constructor,
9737 duk_bi_date_constructor_now,
9738 duk_bi_date_constructor_parse,
9739 duk_bi_date_constructor_utc,
9740 duk_bi_date_prototype_get_shared,
9741 duk_bi_date_prototype_get_timezone_offset,
9742 duk_bi_date_prototype_set_shared,
9743 duk_bi_date_prototype_set_time,
9744 duk_bi_date_prototype_to_json,
9745 duk_bi_date_prototype_tostring_shared,
9746 duk_bi_date_prototype_value_of,
9747 duk_bi_duktape_object_act,
9748 duk_bi_duktape_object_compact,
9749 duk_bi_duktape_object_dec,
9750 duk_bi_duktape_object_enc,
9751 duk_bi_duktape_object_fin,
9752 duk_bi_duktape_object_gc,
9753 duk_bi_duktape_object_info,
9754 duk_bi_error_constructor_shared,
9755 duk_bi_error_prototype_filename_getter,
9756 duk_bi_error_prototype_filename_setter,
9757 duk_bi_error_prototype_linenumber_getter,
9758 duk_bi_error_prototype_linenumber_setter,
9759 duk_bi_error_prototype_stack_getter,
9760 duk_bi_error_prototype_stack_setter,
9761 duk_bi_error_prototype_to_string,
9762 duk_bi_function_constructor,
9763 duk_bi_function_prototype,
9764 duk_bi_function_prototype_apply,
9765 duk_bi_function_prototype_bind,
9766 duk_bi_function_prototype_call,
9767 duk_bi_function_prototype_to_string,
9768 duk_bi_global_object_decode_uri,
9769 duk_bi_global_object_decode_uri_component,
9770 duk_bi_global_object_encode_uri,
9771 duk_bi_global_object_encode_uri_component,
9772 duk_bi_global_object_escape,
9773 duk_bi_global_object_eval,
9774 duk_bi_global_object_is_finite,
9775 duk_bi_global_object_is_nan,
9776 duk_bi_global_object_parse_float,
9777 duk_bi_global_object_parse_int,
9778 duk_bi_global_object_unescape,
9779 duk_bi_json_object_parse,
9780 duk_bi_json_object_stringify,
9781 duk_bi_math_object_hypot,
9782 duk_bi_math_object_max,
9783 duk_bi_math_object_min,
9784 duk_bi_math_object_onearg_shared,
9785 duk_bi_math_object_random,
9786 duk_bi_math_object_twoarg_shared,
9787 duk_bi_nodejs_buffer_byte_length,
9788 duk_bi_nodejs_buffer_concat,
9789 duk_bi_nodejs_buffer_constructor,
9790 duk_bi_nodejs_buffer_copy,
9791 duk_bi_nodejs_buffer_fill,
9792 duk_bi_nodejs_buffer_is_buffer,
9793 duk_bi_nodejs_buffer_is_encoding,
9794 duk_bi_nodejs_buffer_tojson,
9795 duk_bi_nodejs_buffer_tostring,
9796 duk_bi_nodejs_buffer_write,
9797 duk_bi_number_constructor,
9798 duk_bi_number_prototype_to_exponential,
9799 duk_bi_number_prototype_to_fixed,
9800 duk_bi_number_prototype_to_locale_string,
9801 duk_bi_number_prototype_to_precision,
9802 duk_bi_number_prototype_to_string,
9803 duk_bi_number_prototype_value_of,
9804 duk_bi_object_constructor,
9805 duk_bi_object_constructor_assign,
9806 duk_bi_object_constructor_create,
9807 duk_bi_object_constructor_define_properties,
9808 duk_bi_object_constructor_define_property,
9809 duk_bi_object_constructor_get_own_property_descriptor,
9810 duk_bi_object_constructor_is,
9811 duk_bi_object_constructor_is_extensible,
9812 duk_bi_object_constructor_is_sealed_frozen_shared,
9813 duk_bi_object_constructor_keys_shared,
9814 duk_bi_object_constructor_prevent_extensions,
9815 duk_bi_object_constructor_seal_freeze_shared,
9816 duk_bi_object_getprototype_shared,
9817 duk_bi_object_prototype_has_own_property,
9818 duk_bi_object_prototype_is_prototype_of,
9819 duk_bi_object_prototype_property_is_enumerable,
9820 duk_bi_object_prototype_to_locale_string,
9821 duk_bi_object_prototype_to_string,
9822 duk_bi_object_prototype_value_of,
9823 duk_bi_object_setprototype_shared,
9824 duk_bi_pointer_constructor,
9825 duk_bi_pointer_prototype_tostring_shared,
9826 duk_bi_proxy_constructor,
9827 duk_bi_reflect_object_delete_property,
9828 duk_bi_reflect_object_get,
9829 duk_bi_reflect_object_has,
9830 duk_bi_reflect_object_set,
9831 duk_bi_regexp_constructor,
9832 duk_bi_regexp_prototype_exec,
9833 duk_bi_regexp_prototype_flags,
9834 duk_bi_regexp_prototype_shared_getter,
9835 duk_bi_regexp_prototype_test,
9836 duk_bi_regexp_prototype_tostring,
9837 duk_bi_string_constructor,
9838 duk_bi_string_constructor_from_char_code,
9839 duk_bi_string_constructor_from_code_point,
9840 duk_bi_string_prototype_caseconv_shared,
9841 duk_bi_string_prototype_char_at,
9842 duk_bi_string_prototype_char_code_at,
9843 duk_bi_string_prototype_concat,
9844 duk_bi_string_prototype_indexof_shared,
9845 duk_bi_string_prototype_locale_compare,
9846 duk_bi_string_prototype_match,
9847 duk_bi_string_prototype_repeat,
9848 duk_bi_string_prototype_replace,
9849 duk_bi_string_prototype_search,
9850 duk_bi_string_prototype_slice,
9851 duk_bi_string_prototype_split,
9852 duk_bi_string_prototype_substr,
9853 duk_bi_string_prototype_substring,
9854 duk_bi_string_prototype_to_string,
9855 duk_bi_string_prototype_trim,
9856 duk_bi_textdecoder_constructor,
9857 duk_bi_textdecoder_prototype_decode,
9858 duk_bi_textdecoder_prototype_shared_getter,
9859 duk_bi_textencoder_constructor,
9860 duk_bi_textencoder_prototype_encode,
9861 duk_bi_textencoder_prototype_encoding_getter,
9862 duk_bi_thread_constructor,
9863 duk_bi_thread_current,
9864 duk_bi_thread_resume,
9865 duk_bi_thread_yield,
9866 duk_bi_type_error_thrower,
9867 duk_bi_typedarray_buffer_getter,
9868 duk_bi_typedarray_bytelength_getter,
9869 duk_bi_typedarray_byteoffset_getter,
9870 duk_bi_typedarray_constructor,
9871 duk_bi_typedarray_set,
9872 duk_bi_uint8array_allocplain,
9873 duk_bi_uint8array_plainof,
9874};
9875#if defined(DUK_USE_DOUBLE_LE)
9876DUK_INTERNAL const duk_uint8_t duk_builtins_data[3790] = {
9877144,148,105,221,32,68,52,228,62,12,104,200,165,134,148,248,81,77,61,191,
9878135,35,154,103,34,72,6,157,159,197,145,77,245,126,52,130,106,234,163,196,
987952,226,18,51,161,26,113,1,60,37,64,190,18,49,116,116,33,26,113,1,92,136,26,
988098,112,145,139,163,165,8,211,136,14,228,72,82,68,141,17,56,72,197,209,212,
9881132,105,196,5,242,88,108,193,126,18,49,116,117,161,26,113,1,60,158,30,78,
988218,49,116,118,33,26,113,1,29,164,80,78,198,46,142,212,36,68,51,71,224,59,
9883147,60,93,110,79,15,39,9,24,186,33,13,63,79,185,39,26,121,223,110,77,66,53,
9884116,1,120,248,186,248,136,67,76,196,200,134,186,137,177,13,31,192,174,79,
988515,32,248,8,196,24,8,107,254,39,97,161,175,248,159,16,215,252,80,186,26,
9886255,138,57,136,107,254,41,100,33,175,248,167,170,134,191,226,166,138,26,
9887255,138,187,40,107,254,43,111,33,171,86,181,16,209,241,11,228,201,121,240,
9888141,19,134,72,196,52,123,168,95,38,75,207,131,32,156,50,70,33,195,3,152,
9889128,0,0,0,0,0,1,240,255,153,128,0,0,0,0,0,1,224,255,151,137,0,214,9,188,35,
9890131,12,225,196,56,177,78,60,99,147,28,229,200,57,162,120,74,129,124,36,98,
9891232,156,241,92,136,26,98,112,145,139,162,116,71,114,36,41,34,70,136,156,36,
989298,232,157,49,124,150,27,48,95,132,140,93,19,170,39,147,195,201,194,70,46,
9893137,215,17,218,69,4,236,98,232,157,153,39,110,81,220,15,193,209,83,3,200,
9894119,130,241,241,117,240,120,80,252,137,10,178,10,103,134,180,122,9,135,136,
9895154,120,169,199,142,158,121,10,7,146,162,121,74,71,150,166,121,138,135,154,
9896170,121,202,199,158,23,201,146,243,225,26,39,12,145,61,16,190,76,151,159,6,
989765,56,100,137,233,35,93,205,144,33,224,140,137,196,54,121,244,5,60,17,145,
989856,85,184,19,207,16,21,18,227,65,198,231,72,16,137,112,168,106,38,76,225,2,
989970,65,56,100,237,34,140,177,4,134,65,56,100,237,34,129,117,204,123,154,70,
9900207,46,64,146,52,78,25,59,72,163,48,65,34,52,78,25,59,72,160,93,115,30,230,
9901145,179,204,144,24,146,16,30,76,209,2,40,210,72,64,121,52,4,0,156,88,97,5,
9902194,96,227,18,124,124,93,55,79,15,39,28,94,49,38,159,154,136,96,196,159,29,
9903102,241,241,115,201,25,227,131,36,133,20,62,110,142,253,2,102,36,248,235,
990455,143,139,158,72,207,28,104,24,73,112,201,3,2,82,65,155,187,94,6,20,72,9,
9905147,120,128,225,144,168,105,56,248,185,228,140,241,190,96,128,200,84,52,
9906156,124,92,242,70,104,36,183,168,4,145,0,190,41,1,139,18,19,36,226,146,17,
9907124,73,82,54,124,37,230,70,201,14,108,184,132,8,68,185,34,1,100,31,8,129,8,
9908151,11,23,100,141,225,18,12,68,184,75,204,141,146,2,178,112,72,8,162,98,92,
990950,10,152,147,227,172,222,62,46,121,35,60,114,88,96,92,185,112,201,65,34,
991092,4,1,147,81,159,141,205,32,234,121,96,97,57,64,97,121,128,14,56,37,199,
991189,188,124,92,242,70,120,227,144,53,18,227,226,233,186,120,121,56,226,242,
99128,40,248,185,228,140,241,196,75,132,109,24,72,128,43,39,36,136,48,64,114,0,
9913250,156,168,1,64,247,175,25,36,2,8,11,94,80,248,16,40,104,242,103,200,48,
9914193,3,162,92,4,98,12,41,14,66,40,106,101,1,132,130,8,24,78,104,129,54,62,
991596,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0,178,
991658,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87,129,
9917232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104,201,
9918126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71,132,
99190,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232,46,
992036,29,4,78,69,6,60,226,31,192,7,255,252,24,160,163,11,23,51,130,56,35,193,
992156,100,238,31,6,150,46,103,4,225,147,143,114,27,62,233,241,200,137,182,133,
992242,142,167,216,6,23,216,0,97,28,17,224,39,223,32,80,142,8,240,78,25,56,9,
9923248,8,22,39,12,156,123,144,217,240,19,240,18,6,19,154,32,79,194,124,14,134,
9924140,151,227,139,226,52,11,88,37,62,33,163,37,248,226,248,141,32,213,184,64,
992589,56,39,49,224,137,60,100,5,96,38,35,249,8,15,18,61,96,17,60,200,6,145,1,
992617,31,206,64,89,45,2,39,161,0,178,122,209,63,74,2,101,64,202,113,67,77,235,
992764,92,221,197,186,196,143,4,9,19,188,1,25,187,139,112,128,178,113,110,177,
992835,193,2,68,239,0,46,110,229,30,242,71,130,4,137,222,4,35,55,113,110,16,22,
992978,81,239,36,120,32,72,157,224,64,147,138,25,237,0,52,72,242,2,126,82,3,74,
9930129,148,227,234,66,12,112,28,140,155,104,203,169,158,9,133,158,4,25,36,1,
993161,96,47,181,80,46,132,129,255,255,255,255,255,255,222,254,39,172,67,118,
9932170,5,208,144,0,64,0,0,0,0,0,0,51,16,0,0,0,0,0,0,62,31,200,245,238,146,38,
9933138,147,105,13,42,26,137,226,0,0,0,0,0,0,7,131,249,30,180,134,4,209,82,109,
993433,165,67,81,60,64,0,0,0,0,0,0,240,255,28,144,155,104,0,0,0,0,0,0,0,0,16,
9935117,59,130,48,155,98,48,187,144,3,205,220,42,46,65,237,72,27,55,112,151,
9936123,154,70,205,0,94,208,129,115,119,31,18,9,18,67,155,183,34,12,176,96,175,
99374,100,74,228,3,237,38,43,31,192,109,117,171,0,228,164,219,72,0,0,0,0,0,0,
9938248,127,196,234,111,0,50,110,224,193,50,114,83,138,26,107,192,131,38,238,
993977,12,39,37,56,161,166,188,11,132,188,12,74,110,226,220,32,44,156,24,38,78,
994074,113,67,77,120,28,148,221,197,184,64,89,57,52,48,156,148,226,134,154,240,
994164,195,94,8,56,123,193,11,85,116,140,45,240,3,152,147,228,208,194,95,0,89,
9942137,62,22,139,95,48,64,70,200,67,28,98,79,180,152,139,218,45,124,193,1,27,
994333,16,65,137,62,49,205,153,236,132,81,102,36,251,73,137,157,115,102,123,33,
994424,57,137,62,12,19,37,144,142,40,196,159,105,49,15,160,153,44,132,128,198,
994536,248,48,98,200,73,18,98,79,180,152,135,208,98,200,74,16,98,79,135,117,35,
994643,33,44,89,137,62,210,98,63,93,72,202,200,76,20,98,79,140,67,105,50,74,
9947200,77,26,98,79,180,152,153,212,54,147,36,172,132,225,70,36,249,34,9,205,
994828,172,132,241,166,36,251,73,138,93,32,156,209,202,200,80,30,98,79,140,66,
9949214,137,16,78,104,229,100,40,146,49,39,218,76,76,234,22,180,72,130,115,71,
995043,33,72,137,137,62,77,12,38,92,210,113,197,44,137,59,64,7,145,39,201,161,
9951132,184,64,249,18,124,98,22,180,72,130,115,71,43,101,76,148,137,62,210,98,
9952103,80,181,162,68,19,154,57,91,42,130,164,73,242,68,19,154,57,91,95,84,108,
9953137,62,210,98,151,72,39,52,114,182,190,176,169,18,124,98,27,73,146,86,223,
9954215,27,34,79,180,152,153,212,54,147,36,173,191,176,34,68,159,14,234,70,86,
9955231,217,23,34,79,180,152,143,215,82,50,183,62,208,121,18,124,24,38,75,101,
9956108,84,137,62,210,98,31,65,50,91,43,130,36,73,241,142,108,207,109,125,209,
9957114,36,251,73,137,157,115,102,123,107,239,11,145,39,194,209,107,230,8,8,
9958219,127,124,116,137,62,210,98,47,104,181,243,4,4,109,191,192,135,49,39,204,
995916,17,178,24,32,242,36,249,130,2,54,203,7,6,104,14,76,131,140,144,0,0,0,0,
99600,0,0,1,141,207,215,12,78,126,193,46,190,126,192,98,179,246,4,197,231,236,
996110,193,9,114,11,172,64,73,146,83,236,145,169,237,1,6,120,14,78,129,179,40,
9962249,18,149,175,207,141,199,27,76,248,156,81,177,207,139,198,9,169,199,129,
996358,136,19,202,11,179,20,240,149,2,248,72,197,209,200,148,162,117,48,39,148,
9964151,102,42,228,64,211,19,132,140,93,28,137,74,39,85,2,121,81,118,98,238,68,
9965133,36,72,209,19,132,140,93,28,137,74,39,87,2,121,89,118,98,190,75,13,152,
996647,194,70,46,142,68,165,19,172,129,60,176,187,49,79,39,135,147,132,140,93,
996728,137,74,39,91,2,121,105,118,98,142,210,40,39,99,23,71,34,82,135,8,128,
9968120,72,13,42,226,145,97,87,224,168,1,58,182,232,232,64,22,85,181,187,177,
9969107,2,64,7,213,183,74,7,121,207,215,242,17,119,49,248,94,173,198,210,36,15,
9970232,34,182,84,113,95,115,240,221,91,141,163,160,72,1,220,164,194,175,121,
9971123,103,224,186,244,64,24,45,68,84,251,33,9,64,15,217,66,51,209,218,210,
9972129,154,118,254,205,61,65,204,126,23,178,132,103,165,3,52,237,253,154,122,
9973131,216,252,167,224,121,44,48,46,95,203,166,238,74,113,67,77,201,128,219,
9974152,164,82,6,0,203,76,64,64,9,210,211,18,4,4,144,221,49,40,64,76,13,211,19,
99755,4,192,221,45,66,1,4,24,207,76,82,2,8,136,94,152,156,24,157,45,49,64,6,75,
9976191,76,80,66,149,110,116,116,197,8,41,240,247,79,70,188,6,183,27,76,80,194,
997745,198,210,211,20,144,171,113,180,116,52,197,40,27,1,125,34,240,27,16,221,
997842,240,27,221,109,66,32,104,129,163,115,52,224,5,139,168,209,233,138,32,57,
997933,186,98,138,18,80,140,244,197,24,28,192,221,49,71,11,56,209,162,211,20,
9980183,1,66,188,17,145,52,40,9,148,226,134,153,5,198,137,136,32,14,12,30,164,
9981140,144,230,192,0,0,0,0,0,136,211,64,182,120,43,135,126,16,68,52,174,195,
9982144,12,2,158,4,128,70,22,24,128,101,67,112,163,192,100,104,176,131,192,99,
998332,176,99,192,226,115,30,1,79,4,68,28,16,54,0,0,41,254,232,116,62,204,7,21,
998435,18,54,127,80,28,192,132,28,32,14,96,197,212,243,193,48,188,240,39,130,
9985236,224,175,131,117,2,178,112,145,139,163,145,131,114,70,46,142,218,27,182,
998672,197,209,219,56,26,53,161,166,32,128,56,18,2,129,239,94,50,76,130,68,230,
9987202,113,160,167,146,94,163,134,66,161,164,227,226,231,146,51,198,249,147,
998871,209,67,73,210,94,24,49,39,199,89,188,124,92,242,70,120,224,201,33,69,15,
9989155,163,191,68,28,98,79,143,139,166,233,225,228,227,139,198,37,210,244,208,
999024,137,112,151,153,27,36,5,100,224,146,105,184,100,196,95,18,84,141,159,9,
9991121,145,178,67,155,46,33,38,187,168,252,211,243,81,92,2,14,40,16,50,37,202,
9992160,150,154,67,152,148,20,28,76,156,89,26,105,158,63,232,16,44,150,129,18,
9993146,44,28,96,14,98,216,80,113,50,113,100,105,166,120,255,160,20,28,76,156,
9994113,75,34,78,63,236,3,6,133,41,35,31,242,18,195,152,147,226,27,61,138,41,
9995140,16,98,79,148,67,103,177,69,45,136,49,39,196,54,122,58,212,83,26,36,196,
9996159,40,134,207,71,90,138,92,16,98,79,136,108,244,244,168,166,56,73,137,62,
999781,13,158,158,149,20,186,40,196,159,10,183,2,122,122,84,82,240,163,18,124,
999842,220,9,235,106,81,75,225,228,73,241,13,158,197,54,198,8,145,39,202,33,
9999179,216,166,214,196,72,147,226,27,61,29,106,109,141,19,34,79,148,67,103,
10000163,173,77,174,8,145,39,196,54,122,122,84,219,28,38,68,159,40,134,207,79,
1000174,155,93,21,34,79,133,91,129,61,61,42,109,120,84,137,62,21,110,4,245,181,
1000241,181,248,56,224,28,24,80,113,50,113,100,105,166,120,255,160,20,28,76,156,
10003113,75,34,78,63,236,3,6,133,41,35,31,242,11,174,254,160,34,84,8,35,16,98,
10004146,38,55,32,33,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,0,0,0,0,30,
100057,230,56,199,161,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,0,0,0,0,
1000630,7,230,55,36,33,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,0,0,0,0,
1000730,7,234,40,11,91,133,199,172,8,111,248,128,239,88,16,222,56,191,242,49,
10008198,69,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,240,63,
1000949,185,65,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,240,
1001063,49,198,77,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,0,
10011240,63,49,185,97,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,
100120,0,64,49,198,85,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,0,
100130,0,64,49,185,129,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,
100140,0,0,64,49,198,93,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,0,
100150,0,0,64,49,185,161,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,
100160,0,0,16,64,49,198,101,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,
100170,0,0,0,16,64,49,185,193,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,
100180,0,0,0,0,16,64,49,198,109,8,244,56,153,37,180,242,71,104,139,35,8,217,192,
100190,0,0,0,0,0,16,64,49,185,225,8,244,56,153,37,180,242,71,104,139,35,8,217,
10020192,0,0,0,0,0,0,16,64,49,198,117,8,244,56,153,37,180,242,71,104,139,35,8,
10021217,192,0,0,0,0,0,0,16,64,49,186,1,8,244,56,153,37,180,242,71,104,139,35,8,
10022217,192,0,0,0,0,0,0,32,64,49,198,125,8,244,56,153,37,180,242,71,104,139,35,
100238,217,192,0,0,0,0,0,0,32,64,32,232,130,0,97,57,162,4,245,72,10,68,184,70,
10024137,195,67,77,175,32,66,37,192,208,165,36,117,196,10,14,38,78,44,141,52,
10025207,169,64,56,156,199,130,36,160,141,146,52,38,32,76,72,1,246,136,235,103,
10026177,69,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,171,37,
1002720,65,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,158,142,
10028183,86,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,246,136,
10029235,103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161,37,20,
10030138,46,36,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,75,161,
1003137,20,170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,39,208,
10032146,138,70,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,129,89,
1003358,18,81,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,17,214,
10034207,161,37,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,207,
10035161,37,22,176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134,207,
1003698,155,75,27,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38,78,
10037209,29,108,244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213,146,
10038155,76,25,104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39,104,
10039142,182,122,122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208,146,
10040155,69,25,104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16,217,
10041233,233,116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101,162,
10042137,147,133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201,77,
10043156,109,162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68,117,
10044179,234,201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104,162,
10045100,226,27,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,59,22,
1004653,91,0,2,21,11,94,181,128,196,133,0,185,80,32,56,156,199,130,36,160,72,16,
1004778,126,53,144,5,146,208,34,82,72,1,109,20,76,155,40,32,233,0,115,70,130,8,
10048209,56,104,105,187,252,193,3,17,162,112,201,242,18,65,211,0,230,149,132,17,
10049162,112,208,211,119,248,0,82,130,96,95,127,128,130,80,102,186,36,232,92,
10050206,255,1,80,48,200,39,12,158,241,64,
10051};
10052#elif defined(DUK_USE_DOUBLE_BE)
10053DUK_INTERNAL const duk_uint8_t duk_builtins_data[3790] = {
10054144,148,105,221,32,68,52,228,62,12,104,200,165,134,148,248,81,77,61,191,
10055135,35,154,103,34,72,6,157,159,197,145,77,245,126,52,130,106,234,163,196,
1005652,226,18,51,161,26,113,1,60,37,64,190,18,49,116,116,33,26,113,1,92,136,26,
1005798,112,145,139,163,165,8,211,136,14,228,72,82,68,141,17,56,72,197,209,212,
10058132,105,196,5,242,88,108,193,126,18,49,116,117,161,26,113,1,60,158,30,78,
1005918,49,116,118,33,26,113,1,29,164,80,78,198,46,142,212,36,68,51,71,224,59,
10060147,60,93,110,79,15,39,9,24,186,33,13,63,79,185,39,26,121,223,110,77,66,53,
10061116,1,120,248,186,248,136,67,76,196,200,134,186,137,177,13,31,192,174,79,
1006215,32,248,8,196,24,8,107,254,39,97,161,175,248,159,16,215,252,80,186,26,
10063255,138,57,136,107,254,41,100,33,175,248,167,170,134,191,226,166,138,26,
10064255,138,187,40,107,254,43,111,33,171,86,181,16,209,241,11,228,201,121,240,
10065141,19,134,72,196,52,123,168,95,38,75,207,131,32,156,50,70,33,195,3,152,
10066128,255,240,0,0,0,0,0,1,153,128,255,224,0,0,0,0,0,1,151,137,0,214,9,188,35,
10067131,12,225,196,56,177,78,60,99,147,28,229,200,57,162,120,74,129,124,36,98,
10068232,156,241,92,136,26,98,112,145,139,162,116,71,114,36,41,34,70,136,156,36,
1006998,232,157,49,124,150,27,48,95,132,140,93,19,170,39,147,195,201,194,70,46,
10070137,215,17,218,69,4,236,98,232,157,153,39,110,81,220,15,193,209,83,3,200,
10071119,130,241,241,117,240,120,80,252,137,10,178,10,103,134,180,122,9,135,136,
10072154,120,169,199,142,158,121,10,7,146,162,121,74,71,150,166,121,138,135,154,
10073170,121,202,199,158,23,201,146,243,225,26,39,12,145,61,16,190,76,151,159,6,
1007465,56,100,137,233,35,93,205,144,33,224,140,137,196,54,121,244,5,60,17,145,
1007556,85,184,19,207,16,21,18,227,65,198,231,72,16,137,112,168,106,38,76,225,2,
1007670,65,56,100,237,34,140,177,4,134,65,56,100,237,34,129,117,204,123,154,70,
10077207,46,64,146,52,78,25,59,72,163,48,65,34,52,78,25,59,72,160,93,115,30,230,
10078145,179,204,144,24,146,16,30,76,209,2,40,210,72,64,121,52,4,0,156,88,97,5,
10079194,96,227,18,124,124,93,55,79,15,39,28,94,49,38,159,154,136,96,196,159,29,
10080102,241,241,115,201,25,227,131,36,133,20,62,110,142,253,2,102,36,248,235,
1008155,143,139,158,72,207,28,104,24,73,112,201,3,2,82,65,155,187,94,6,20,72,9,
10082147,120,128,225,144,168,105,56,248,185,228,140,241,190,96,128,200,84,52,
10083156,124,92,242,70,104,36,183,168,4,145,0,190,41,1,139,18,19,36,226,146,17,
10084124,73,82,54,124,37,230,70,201,14,108,184,132,8,68,185,34,1,100,31,8,129,8,
10085151,11,23,100,141,225,18,12,68,184,75,204,141,146,2,178,112,72,8,162,98,92,
1008650,10,152,147,227,172,222,62,46,121,35,60,114,88,96,92,185,112,201,65,34,
1008792,4,1,147,81,159,141,205,32,234,121,96,97,57,64,97,121,128,14,56,37,199,
1008889,188,124,92,242,70,120,227,144,53,18,227,226,233,186,120,121,56,226,242,
100898,40,248,185,228,140,241,196,75,132,109,24,72,128,43,39,36,136,48,64,114,0,
10090250,156,168,1,64,247,175,25,36,2,8,11,94,80,248,16,40,104,242,103,200,48,
10091193,3,162,92,4,98,12,41,14,66,40,106,101,1,132,130,8,24,78,104,129,54,62,
1009296,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0,178,
1009358,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87,129,
10094232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104,201,
10095126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71,132,
100960,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232,46,
1009736,29,4,78,69,6,60,226,31,192,7,255,252,24,160,163,11,23,51,130,56,35,193,
1009856,100,238,31,6,150,46,103,4,225,147,143,114,27,62,233,241,200,137,182,133,
1009942,142,167,216,6,23,216,0,97,28,17,224,39,223,32,80,142,8,240,78,25,56,9,
10100248,8,22,39,12,156,123,144,217,240,19,240,18,6,19,154,32,79,194,124,14,134,
10101140,151,227,139,226,52,11,88,37,62,33,163,37,248,226,248,141,32,213,184,64,
1010289,56,39,49,224,137,60,100,5,96,38,35,249,8,15,18,61,96,17,60,200,6,145,1,
1010317,31,206,64,89,45,2,39,161,0,178,122,209,63,74,2,101,64,202,113,67,77,235,
1010464,92,221,197,186,196,143,4,9,19,188,1,25,187,139,112,128,178,113,110,177,
1010535,193,2,68,239,0,46,110,229,30,242,71,130,4,137,222,4,35,55,113,110,16,22,
1010678,81,239,36,120,32,72,157,224,64,147,138,25,237,0,52,72,242,2,126,82,3,74,
10107129,148,227,234,66,12,112,28,140,155,104,203,169,158,9,133,158,4,25,36,1,
1010861,96,47,181,80,46,132,128,255,223,255,255,255,255,255,254,39,172,67,118,
10109170,5,208,144,0,0,0,0,0,0,0,0,115,16,31,254,0,0,0,0,0,0,8,245,238,146,38,
10110138,147,105,13,42,26,137,226,3,255,128,0,0,0,0,0,1,30,180,134,4,209,82,109,
1011133,165,67,81,60,64,255,240,0,0,0,0,0,0,28,144,155,104,0,0,0,0,0,0,0,0,16,
10112117,59,130,48,155,98,48,187,144,3,205,220,42,46,65,237,72,27,55,112,151,
10113123,154,70,205,0,94,208,129,115,119,31,18,9,18,67,155,183,34,12,176,96,175,
101144,100,74,228,3,237,38,43,31,192,109,117,171,0,228,164,219,72,127,248,0,0,0,
101150,0,0,196,234,111,0,50,110,224,193,50,114,83,138,26,107,192,131,38,238,77,
1011612,39,37,56,161,166,188,11,132,188,12,74,110,226,220,32,44,156,24,38,78,74,
10117113,67,77,120,28,148,221,197,184,64,89,57,52,48,156,148,226,134,154,240,64,
10118195,94,8,56,123,193,11,85,116,140,45,240,3,152,147,228,208,194,95,0,89,137,
1011962,22,139,95,48,64,70,200,67,28,98,79,180,152,139,218,45,124,193,1,27,33,
1012016,65,137,62,49,205,153,236,132,81,102,36,251,73,137,157,115,102,123,33,24,
1012157,137,62,12,19,37,144,142,40,196,159,105,49,15,160,153,44,132,128,198,36,
10122248,48,98,200,73,18,98,79,180,152,135,208,98,200,74,16,98,79,135,117,35,43,
1012333,44,89,137,62,210,98,63,93,72,202,200,76,20,98,79,140,67,105,50,74,200,
1012477,26,98,79,180,152,153,212,54,147,36,172,132,225,70,36,249,34,9,205,28,
10125172,132,241,166,36,251,73,138,93,32,156,209,202,200,80,30,98,79,140,66,214,
10126137,16,78,104,229,100,40,146,49,39,218,76,76,234,22,180,72,130,115,71,43,
1012733,72,137,137,62,77,12,38,92,210,113,197,44,137,59,64,7,145,39,201,161,132,
10128184,64,249,18,124,98,22,180,72,130,115,71,43,101,76,148,137,62,210,98,103,
1012980,181,162,68,19,154,57,91,42,130,164,73,242,68,19,154,57,91,95,84,108,137,
1013062,210,98,151,72,39,52,114,182,190,176,169,18,124,98,27,73,146,86,223,215,
1013127,34,79,180,152,153,212,54,147,36,173,191,176,34,68,159,14,234,70,86,231,
10132217,23,34,79,180,152,143,215,82,50,183,62,208,121,18,124,24,38,75,101,108,
1013384,137,62,210,98,31,65,50,91,43,130,36,73,241,142,108,207,109,125,209,114,
1013436,251,73,137,157,115,102,123,107,239,11,145,39,194,209,107,230,8,8,219,
10135127,124,116,137,62,210,98,47,104,181,243,4,4,109,191,192,135,49,39,204,16,
1013617,178,24,32,242,36,249,130,2,54,203,7,6,104,14,76,131,140,144,0,0,0,0,0,0,
101370,1,141,207,215,12,78,126,193,46,190,126,192,98,179,246,4,197,231,236,10,
10138193,9,114,11,172,64,73,146,83,236,145,169,237,1,6,120,14,78,129,179,40,249,
1013918,149,175,207,141,199,27,76,248,156,81,177,207,139,198,9,169,199,129,58,
10140136,19,202,11,179,20,240,149,2,248,72,197,209,200,148,162,117,48,39,148,
10141151,102,42,228,64,211,19,132,140,93,28,137,74,39,85,2,121,81,118,98,238,68,
10142133,36,72,209,19,132,140,93,28,137,74,39,87,2,121,89,118,98,190,75,13,152,
1014347,194,70,46,142,68,165,19,172,129,60,176,187,49,79,39,135,147,132,140,93,
1014428,137,74,39,91,2,121,105,118,98,142,210,40,39,99,23,71,34,82,135,8,128,
10145120,72,8,0,183,225,81,98,138,237,33,58,182,232,232,64,64,2,107,177,187,181,
1014685,22,7,213,183,74,1,255,49,114,23,247,209,207,120,94,173,198,210,36,3,255,
10147113,84,118,82,184,47,224,221,91,141,163,160,72,7,251,121,111,98,164,220,
10148161,192,186,244,64,64,9,33,251,84,68,45,24,15,217,66,51,209,218,210,128,
10149127,205,65,60,204,254,119,154,23,178,132,103,165,0,255,218,130,121,153,252,
10150239,52,167,224,121,44,48,46,95,203,166,238,74,113,67,77,201,128,219,152,
10151164,82,6,0,203,76,64,64,9,210,211,18,4,4,144,221,49,40,64,76,13,211,19,5,4,
10152192,221,45,66,1,4,24,207,76,82,2,8,136,94,152,156,24,157,45,49,64,6,75,191,
1015376,80,66,149,110,116,116,197,8,41,240,247,79,70,188,6,183,27,76,80,194,45,
10154198,210,211,20,144,171,113,180,116,52,197,40,27,1,125,34,240,27,16,221,42,
10155240,27,221,109,66,32,104,129,163,115,52,224,5,139,168,209,233,138,32,57,33,
10156186,98,138,18,80,140,244,197,24,28,192,221,49,71,11,56,209,162,211,20,183,
101571,66,188,17,145,52,40,9,148,226,134,153,5,198,137,136,32,14,12,30,164,140,
10158144,230,192,64,211,136,0,0,0,0,0,182,120,43,135,126,16,68,52,174,195,144,
1015912,2,158,4,128,70,22,24,128,101,67,112,163,192,100,104,176,131,192,99,32,
10160176,99,192,226,115,30,1,79,4,68,28,16,54,0,0,41,254,232,116,62,204,7,21,35,
1016118,54,127,80,28,192,132,28,32,14,96,197,212,243,193,48,188,240,39,130,236,
10162224,175,131,117,2,178,112,145,139,163,145,131,114,70,46,142,218,27,182,72,
10163197,209,219,56,26,53,161,166,32,128,56,18,2,129,239,94,50,76,130,68,230,
10164202,113,160,167,146,94,163,134,66,161,164,227,226,231,146,51,198,249,147,
1016571,209,67,73,210,94,24,49,39,199,89,188,124,92,242,70,120,224,201,33,69,15,
10166155,163,191,68,28,98,79,143,139,166,233,225,228,227,139,198,37,210,244,208,
1016724,137,112,151,153,27,36,5,100,224,146,105,184,100,196,95,18,84,141,159,9,
10168121,145,178,67,155,46,33,38,187,168,252,211,243,81,92,2,14,40,16,50,37,202,
10169160,150,154,67,152,148,20,28,76,156,89,26,105,158,63,232,16,44,150,129,18,
10170146,44,28,96,14,98,216,80,113,50,113,100,105,166,120,255,160,20,28,76,156,
10171113,75,34,78,63,236,3,6,133,41,35,31,242,18,195,152,147,226,27,61,138,41,
10172140,16,98,79,148,67,103,177,69,45,136,49,39,196,54,122,58,212,83,26,36,196,
10173159,40,134,207,71,90,138,92,16,98,79,136,108,244,244,168,166,56,73,137,62,
1017481,13,158,158,149,20,186,40,196,159,10,183,2,122,122,84,82,240,163,18,124,
1017542,220,9,235,106,81,75,225,228,73,241,13,158,197,54,198,8,145,39,202,33,
10176179,216,166,214,196,72,147,226,27,61,29,106,109,141,19,34,79,148,67,103,
10177163,173,77,174,8,145,39,196,54,122,122,84,219,28,38,68,159,40,134,207,79,
1017874,155,93,21,34,79,133,91,129,61,61,42,109,120,84,137,62,21,110,4,245,181,
1017941,181,248,56,224,28,24,80,113,50,113,100,105,166,120,255,160,20,28,76,156,
10180113,75,34,78,63,236,3,6,133,41,35,31,242,11,174,254,160,34,84,8,35,16,98,
10181146,38,55,32,33,30,135,19,36,182,158,72,237,17,100,97,27,56,7,254,0,0,0,0,
101820,0,6,56,199,161,30,135,19,36,182,158,72,237,17,100,97,27,56,7,254,0,0,0,0,
101830,0,6,55,36,33,30,135,19,36,182,158,72,237,17,100,97,27,56,7,254,0,0,0,0,0,
101840,10,40,11,91,133,199,172,8,111,248,128,239,88,16,222,56,191,242,49,198,69,
101858,244,56,153,37,180,242,71,104,139,35,8,217,192,63,240,0,0,0,0,0,0,49,185,
1018665,8,244,56,153,37,180,242,71,104,139,35,8,217,192,63,240,0,0,0,0,0,0,49,
10187198,77,8,244,56,153,37,180,242,71,104,139,35,8,217,192,63,240,0,0,0,0,0,0,
1018849,185,97,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,0,0,0,0,0,0,0,
1018949,198,85,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,0,0,0,0,0,0,0,
1019049,185,129,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,0,0,0,0,0,0,
101910,49,198,93,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,0,0,0,0,0,0,
101920,49,185,161,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0,0,0,0,
101930,0,49,198,101,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0,0,0,
101940,0,0,49,185,193,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0,0,
101950,0,0,0,49,198,109,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,0,
101960,0,0,0,0,49,185,225,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,16,
101970,0,0,0,0,0,49,198,117,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,
1019816,0,0,0,0,0,0,49,186,1,8,244,56,153,37,180,242,71,104,139,35,8,217,192,64,
1019932,0,0,0,0,0,0,49,198,125,8,244,56,153,37,180,242,71,104,139,35,8,217,192,
1020064,32,0,0,0,0,0,0,32,232,130,0,97,57,162,4,245,72,10,68,184,70,137,195,67,
1020177,175,32,66,37,192,208,165,36,117,196,10,14,38,78,44,141,52,207,169,64,56,
10202156,199,130,36,160,141,146,52,38,32,76,72,1,246,136,235,103,177,69,1,17,32,
102037,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,171,37,20,65,145,32,7,
10204218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,158,142,183,86,74,41,48,
1020592,72,1,241,13,158,142,183,66,74,41,80,100,72,1,246,136,235,103,167,165,
10206213,146,138,40,200,144,3,237,17,214,207,79,75,161,37,20,138,46,36,0,248,
10207134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,75,161,37,20,170,46,36,
102080,248,85,184,19,234,201,69,24,92,72,1,240,171,112,39,208,146,138,70,25,18,
102090,124,27,168,21,147,171,37,20,113,145,32,7,193,186,129,89,58,18,81,72,226,
10210162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,17,214,207,161,37,22,144,
1021138,36,0,248,134,207,171,37,22,160,38,36,0,248,134,207,161,37,22,176,42,209,
1021268,201,218,35,173,158,197,54,4,218,40,153,56,134,207,98,155,75,27,104,162,
10213100,237,17,214,207,71,91,171,37,54,65,182,138,38,78,209,29,108,244,117,186,
1021418,83,104,131,45,20,76,156,67,103,163,173,213,146,155,76,25,104,162,100,
10215226,27,61,29,110,132,148,218,160,219,69,19,39,104,142,182,122,122,93,89,41,
10216178,141,180,81,50,118,136,235,103,167,165,208,146,155,69,25,104,162,100,
10217226,27,61,61,46,172,148,218,104,203,69,19,39,16,217,233,233,116,36,166,213,
1021870,90,40,153,56,85,184,19,234,201,77,152,101,162,137,147,133,91,129,62,132,
10219148,218,48,219,69,19,39,6,234,5,100,234,201,77,156,109,162,137,147,131,117,
102202,178,116,36,166,209,197,218,40,153,59,68,117,179,234,201,78,32,11,180,81,
1022150,118,136,235,103,208,146,156,72,21,104,162,100,226,27,62,172,148,226,128,
10222171,69,19,39,16,217,244,36,167,22,53,59,22,53,91,0,2,21,11,94,181,128,196,
10223133,0,185,80,32,56,156,199,130,36,160,72,16,78,126,53,144,5,146,208,34,82,
1022472,1,109,20,76,155,40,32,233,0,115,70,130,8,209,56,104,105,187,252,193,3,
1022517,162,112,201,242,18,65,211,0,230,149,132,17,162,112,208,211,119,248,0,82,
10226130,96,95,127,128,130,80,102,186,36,232,92,206,255,1,80,48,200,39,12,158,
10227241,64,
10228};
10229#elif defined(DUK_USE_DOUBLE_ME)
10230DUK_INTERNAL const duk_uint8_t duk_builtins_data[3790] = {
10231144,148,105,221,32,68,52,228,62,12,104,200,165,134,148,248,81,77,61,191,
10232135,35,154,103,34,72,6,157,159,197,145,77,245,126,52,130,106,234,163,196,
1023352,226,18,51,161,26,113,1,60,37,64,190,18,49,116,116,33,26,113,1,92,136,26,
1023498,112,145,139,163,165,8,211,136,14,228,72,82,68,141,17,56,72,197,209,212,
10235132,105,196,5,242,88,108,193,126,18,49,116,117,161,26,113,1,60,158,30,78,
1023618,49,116,118,33,26,113,1,29,164,80,78,198,46,142,212,36,68,51,71,224,59,
10237147,60,93,110,79,15,39,9,24,186,33,13,63,79,185,39,26,121,223,110,77,66,53,
10238116,1,120,248,186,248,136,67,76,196,200,134,186,137,177,13,31,192,174,79,
1023915,32,248,8,196,24,8,107,254,39,97,161,175,248,159,16,215,252,80,186,26,
10240255,138,57,136,107,254,41,100,33,175,248,167,170,134,191,226,166,138,26,
10241255,138,187,40,107,254,43,111,33,171,86,181,16,209,241,11,228,201,121,240,
10242141,19,134,72,196,52,123,168,95,38,75,207,131,32,156,50,70,33,195,3,152,
10243128,0,1,240,254,0,0,0,1,153,128,0,1,224,254,0,0,0,1,151,137,0,214,9,188,35,
10244131,12,225,196,56,177,78,60,99,147,28,229,200,57,162,120,74,129,124,36,98,
10245232,156,241,92,136,26,98,112,145,139,162,116,71,114,36,41,34,70,136,156,36,
1024698,232,157,49,124,150,27,48,95,132,140,93,19,170,39,147,195,201,194,70,46,
10247137,215,17,218,69,4,236,98,232,157,153,39,110,81,220,15,193,209,83,3,200,
10248119,130,241,241,117,240,120,80,252,137,10,178,10,103,134,180,122,9,135,136,
10249154,120,169,199,142,158,121,10,7,146,162,121,74,71,150,166,121,138,135,154,
10250170,121,202,199,158,23,201,146,243,225,26,39,12,145,61,16,190,76,151,159,6,
1025165,56,100,137,233,35,93,205,144,33,224,140,137,196,54,121,244,5,60,17,145,
1025256,85,184,19,207,16,21,18,227,65,198,231,72,16,137,112,168,106,38,76,225,2,
1025370,65,56,100,237,34,140,177,4,134,65,56,100,237,34,129,117,204,123,154,70,
10254207,46,64,146,52,78,25,59,72,163,48,65,34,52,78,25,59,72,160,93,115,30,230,
10255145,179,204,144,24,146,16,30,76,209,2,40,210,72,64,121,52,4,0,156,88,97,5,
10256194,96,227,18,124,124,93,55,79,15,39,28,94,49,38,159,154,136,96,196,159,29,
10257102,241,241,115,201,25,227,131,36,133,20,62,110,142,253,2,102,36,248,235,
1025855,143,139,158,72,207,28,104,24,73,112,201,3,2,82,65,155,187,94,6,20,72,9,
10259147,120,128,225,144,168,105,56,248,185,228,140,241,190,96,128,200,84,52,
10260156,124,92,242,70,104,36,183,168,4,145,0,190,41,1,139,18,19,36,226,146,17,
10261124,73,82,54,124,37,230,70,201,14,108,184,132,8,68,185,34,1,100,31,8,129,8,
10262151,11,23,100,141,225,18,12,68,184,75,204,141,146,2,178,112,72,8,162,98,92,
1026350,10,152,147,227,172,222,62,46,121,35,60,114,88,96,92,185,112,201,65,34,
1026492,4,1,147,81,159,141,205,32,234,121,96,97,57,64,97,121,128,14,56,37,199,
1026589,188,124,92,242,70,120,227,144,53,18,227,226,233,186,120,121,56,226,242,
102668,40,248,185,228,140,241,196,75,132,109,24,72,128,43,39,36,136,48,64,114,0,
10267250,156,168,1,64,247,175,25,36,2,8,11,94,80,248,16,40,104,242,103,200,48,
10268193,3,162,92,4,98,12,41,14,66,40,106,101,1,132,130,8,24,78,104,129,54,62,
1026996,224,144,13,238,124,32,2,62,146,60,51,224,120,146,164,140,137,20,0,178,
1027058,11,56,192,5,146,208,34,71,64,36,157,25,200,32,52,158,180,8,146,87,129,
10271232,217,29,5,156,179,224,116,52,100,191,28,87,62,130,214,9,79,136,104,201,
10272126,56,174,127,0,31,255,225,73,82,71,16,13,1,36,230,18,1,164,14,87,71,132,
102730,143,0,210,131,96,31,0,211,6,42,23,50,70,1,167,13,18,14,130,36,67,232,46,
1027436,29,4,78,69,6,60,226,31,192,7,255,252,24,160,163,11,23,51,130,56,35,193,
1027556,100,238,31,6,150,46,103,4,225,147,143,114,27,62,233,241,200,137,182,133,
1027642,142,167,216,6,23,216,0,97,28,17,224,39,223,32,80,142,8,240,78,25,56,9,
10277248,8,22,39,12,156,123,144,217,240,19,240,18,6,19,154,32,79,194,124,14,134,
10278140,151,227,139,226,52,11,88,37,62,33,163,37,248,226,248,141,32,213,184,64,
1027989,56,39,49,224,137,60,100,5,96,38,35,249,8,15,18,61,96,17,60,200,6,145,1,
1028017,31,206,64,89,45,2,39,161,0,178,122,209,63,74,2,101,64,202,113,67,77,235,
1028164,92,221,197,186,196,143,4,9,19,188,1,25,187,139,112,128,178,113,110,177,
1028235,193,2,68,239,0,46,110,229,30,242,71,130,4,137,222,4,35,55,113,110,16,22,
1028378,81,239,36,120,32,72,157,224,64,147,138,25,237,0,52,72,242,2,126,82,3,74,
10284129,148,227,234,66,12,112,28,140,155,104,203,169,158,9,133,158,4,25,36,1,
1028561,96,47,181,80,46,132,129,255,255,222,255,255,255,255,254,39,172,67,118,
10286170,5,208,144,0,0,0,0,0,64,0,0,51,16,0,0,62,31,192,0,0,0,8,245,238,146,38,
10287138,147,105,13,42,26,137,226,0,0,7,131,248,0,0,0,1,30,180,134,4,209,82,109,
1028833,165,67,81,60,64,0,0,240,255,0,0,0,0,28,144,155,104,0,0,0,0,0,0,0,0,16,
10289117,59,130,48,155,98,48,187,144,3,205,220,42,46,65,237,72,27,55,112,151,
10290123,154,70,205,0,94,208,129,115,119,31,18,9,18,67,155,183,34,12,176,96,175,
102914,100,74,228,3,237,38,43,31,192,109,117,171,0,228,164,219,72,0,0,248,127,0,
102920,0,0,196,234,111,0,50,110,224,193,50,114,83,138,26,107,192,131,38,238,77,
1029312,39,37,56,161,166,188,11,132,188,12,74,110,226,220,32,44,156,24,38,78,74,
10294113,67,77,120,28,148,221,197,184,64,89,57,52,48,156,148,226,134,154,240,64,
10295195,94,8,56,123,193,11,85,116,140,45,240,3,152,147,228,208,194,95,0,89,137,
1029662,22,139,95,48,64,70,200,67,28,98,79,180,152,139,218,45,124,193,1,27,33,
1029716,65,137,62,49,205,153,236,132,81,102,36,251,73,137,157,115,102,123,33,24,
1029857,137,62,12,19,37,144,142,40,196,159,105,49,15,160,153,44,132,128,198,36,
10299248,48,98,200,73,18,98,79,180,152,135,208,98,200,74,16,98,79,135,117,35,43,
1030033,44,89,137,62,210,98,63,93,72,202,200,76,20,98,79,140,67,105,50,74,200,
1030177,26,98,79,180,152,153,212,54,147,36,172,132,225,70,36,249,34,9,205,28,
10302172,132,241,166,36,251,73,138,93,32,156,209,202,200,80,30,98,79,140,66,214,
10303137,16,78,104,229,100,40,146,49,39,218,76,76,234,22,180,72,130,115,71,43,
1030433,72,137,137,62,77,12,38,92,210,113,197,44,137,59,64,7,145,39,201,161,132,
10305184,64,249,18,124,98,22,180,72,130,115,71,43,101,76,148,137,62,210,98,103,
1030680,181,162,68,19,154,57,91,42,130,164,73,242,68,19,154,57,91,95,84,108,137,
1030762,210,98,151,72,39,52,114,182,190,176,169,18,124,98,27,73,146,86,223,215,
1030827,34,79,180,152,153,212,54,147,36,173,191,176,34,68,159,14,234,70,86,231,
10309217,23,34,79,180,152,143,215,82,50,183,62,208,121,18,124,24,38,75,101,108,
1031084,137,62,210,98,31,65,50,91,43,130,36,73,241,142,108,207,109,125,209,114,
1031136,251,73,137,157,115,102,123,107,239,11,145,39,194,209,107,230,8,8,219,
10312127,124,116,137,62,210,98,47,104,181,243,4,4,109,191,192,135,49,39,204,16,
1031317,178,24,32,242,36,249,130,2,54,203,7,6,104,14,76,131,140,144,0,0,0,0,0,0,
103140,1,141,207,215,12,78,126,193,46,190,126,192,98,179,246,4,197,231,236,10,
10315193,9,114,11,172,64,73,146,83,236,145,169,237,1,6,120,14,78,129,179,40,249,
1031618,149,175,207,141,199,27,76,248,156,81,177,207,139,198,9,169,199,129,58,
10317136,19,202,11,179,20,240,149,2,248,72,197,209,200,148,162,117,48,39,148,
10318151,102,42,228,64,211,19,132,140,93,28,137,74,39,85,2,121,81,118,98,238,68,
10319133,36,72,209,19,132,140,93,28,137,74,39,87,2,121,89,118,98,190,75,13,152,
1032047,194,70,46,142,68,165,19,172,129,60,176,187,49,79,39,135,147,132,140,93,
1032128,137,74,39,91,2,121,105,118,98,142,210,40,39,99,23,71,34,82,135,8,128,
10322120,72,1,87,224,168,13,42,226,145,97,58,182,232,232,64,177,107,2,64,22,85,
10323181,187,7,213,183,74,2,17,119,49,255,121,207,215,240,94,173,198,210,36,4,
10324113,95,115,255,232,34,182,80,221,91,141,163,160,72,15,121,123,103,225,220,
10325164,194,160,186,244,64,251,33,9,64,24,45,68,84,15,217,66,51,209,218,210,
10326129,61,65,204,127,154,118,254,204,23,178,132,103,165,2,122,131,216,255,52,
10327237,253,152,167,224,121,44,48,46,95,203,166,238,74,113,67,77,201,128,219,
10328152,164,82,6,0,203,76,64,64,9,210,211,18,4,4,144,221,49,40,64,76,13,211,19,
103295,4,192,221,45,66,1,4,24,207,76,82,2,8,136,94,152,156,24,157,45,49,64,6,75,
10330191,76,80,66,149,110,116,116,197,8,41,240,247,79,70,188,6,183,27,76,80,194,
1033145,198,210,211,20,144,171,113,180,116,52,197,40,27,1,125,34,240,27,16,221,
1033242,240,27,221,109,66,32,104,129,163,115,52,224,5,139,168,209,233,138,32,57,
1033333,186,98,138,18,80,140,244,197,24,28,192,221,49,71,11,56,209,162,211,20,
10334183,1,66,188,17,145,52,40,9,148,226,134,153,5,198,137,136,32,14,12,30,164,
10335140,144,230,192,0,136,211,64,0,0,0,0,182,120,43,135,126,16,68,52,174,195,
10336144,12,2,158,4,128,70,22,24,128,101,67,112,163,192,100,104,176,131,192,99,
1033732,176,99,192,226,115,30,1,79,4,68,28,16,54,0,0,41,254,232,116,62,204,7,21,
1033835,18,54,127,80,28,192,132,28,32,14,96,197,212,243,193,48,188,240,39,130,
10339236,224,175,131,117,2,178,112,145,139,163,145,131,114,70,46,142,218,27,182,
1034072,197,209,219,56,26,53,161,166,32,128,56,18,2,129,239,94,50,76,130,68,230,
10341202,113,160,167,146,94,163,134,66,161,164,227,226,231,146,51,198,249,147,
1034271,209,67,73,210,94,24,49,39,199,89,188,124,92,242,70,120,224,201,33,69,15,
10343155,163,191,68,28,98,79,143,139,166,233,225,228,227,139,198,37,210,244,208,
1034424,137,112,151,153,27,36,5,100,224,146,105,184,100,196,95,18,84,141,159,9,
10345121,145,178,67,155,46,33,38,187,168,252,211,243,81,92,2,14,40,16,50,37,202,
10346160,150,154,67,152,148,20,28,76,156,89,26,105,158,63,232,16,44,150,129,18,
10347146,44,28,96,14,98,216,80,113,50,113,100,105,166,120,255,160,20,28,76,156,
10348113,75,34,78,63,236,3,6,133,41,35,31,242,18,195,152,147,226,27,61,138,41,
10349140,16,98,79,148,67,103,177,69,45,136,49,39,196,54,122,58,212,83,26,36,196,
10350159,40,134,207,71,90,138,92,16,98,79,136,108,244,244,168,166,56,73,137,62,
1035181,13,158,158,149,20,186,40,196,159,10,183,2,122,122,84,82,240,163,18,124,
1035242,220,9,235,106,81,75,225,228,73,241,13,158,197,54,198,8,145,39,202,33,
10353179,216,166,214,196,72,147,226,27,61,29,106,109,141,19,34,79,148,67,103,
10354163,173,77,174,8,145,39,196,54,122,122,84,219,28,38,68,159,40,134,207,79,
1035574,155,93,21,34,79,133,91,129,61,61,42,109,120,84,137,62,21,110,4,245,181,
1035641,181,248,56,224,28,24,80,113,50,113,100,105,166,120,255,160,20,28,76,156,
10357113,75,34,78,63,236,3,6,133,41,35,31,242,11,174,254,160,34,84,8,35,16,98,
10358146,38,55,32,33,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,30,7,224,0,
103590,0,6,56,199,161,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,30,7,224,
103600,0,0,6,55,36,33,30,135,19,36,182,158,72,237,17,100,97,27,56,0,0,30,7,224,
103610,0,0,10,40,11,91,133,199,172,8,111,248,128,239,88,16,222,56,191,242,49,
10362198,69,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,240,63,0,0,0,0,
1036349,185,65,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,240,63,0,0,0,
103640,49,198,77,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,240,63,0,0,
103650,0,49,185,97,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,64,0,0,
103660,0,49,198,85,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,64,0,0,
103670,0,49,185,129,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,64,0,
103680,0,0,49,198,93,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,0,64,0,
103690,0,0,49,185,161,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,16,64,
103700,0,0,0,49,198,101,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,16,
1037164,0,0,0,0,49,185,193,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,0,
1037216,64,0,0,0,0,49,198,109,8,244,56,153,37,180,242,71,104,139,35,8,217,192,0,
103730,16,64,0,0,0,0,49,185,225,8,244,56,153,37,180,242,71,104,139,35,8,217,192,
103740,0,16,64,0,0,0,0,49,198,117,8,244,56,153,37,180,242,71,104,139,35,8,217,
10375192,0,0,16,64,0,0,0,0,49,186,1,8,244,56,153,37,180,242,71,104,139,35,8,217,
10376192,0,0,32,64,0,0,0,0,49,198,125,8,244,56,153,37,180,242,71,104,139,35,8,
10377217,192,0,0,32,64,0,0,0,0,32,232,130,0,97,57,162,4,245,72,10,68,184,70,137,
10378195,67,77,175,32,66,37,192,208,165,36,117,196,10,14,38,78,44,141,52,207,
10379169,64,56,156,199,130,36,160,141,146,52,38,32,76,72,1,246,136,235,103,177,
1038069,1,17,32,7,196,54,123,20,82,88,200,144,3,237,17,214,207,71,91,171,37,20,
1038165,145,32,7,218,35,173,158,142,183,66,74,41,16,92,72,1,241,13,158,142,183,
1038286,74,41,48,92,72,1,241,13,158,142,183,66,74,41,80,100,72,1,246,136,235,
10383103,167,165,213,146,138,40,200,144,3,237,17,214,207,79,75,161,37,20,138,46,
1038436,0,248,134,207,79,75,171,37,20,154,46,36,0,248,134,207,79,75,161,37,20,
10385170,46,36,0,248,85,184,19,234,201,69,24,92,72,1,240,171,112,39,208,146,138,
1038670,25,18,0,124,27,168,21,147,171,37,20,113,145,32,7,193,186,129,89,58,18,
1038781,72,226,162,64,15,180,71,91,62,172,148,90,0,168,144,3,237,17,214,207,161,
1038837,22,144,38,36,0,248,134,207,171,37,22,160,38,36,0,248,134,207,161,37,22,
10389176,42,209,68,201,218,35,173,158,197,54,4,218,40,153,56,134,207,98,155,75,
1039027,104,162,100,237,17,214,207,71,91,171,37,54,65,182,138,38,78,209,29,108,
10391244,117,186,18,83,104,131,45,20,76,156,67,103,163,173,213,146,155,76,25,
10392104,162,100,226,27,61,29,110,132,148,218,160,219,69,19,39,104,142,182,122,
10393122,93,89,41,178,141,180,81,50,118,136,235,103,167,165,208,146,155,69,25,
10394104,162,100,226,27,61,61,46,172,148,218,104,203,69,19,39,16,217,233,233,
10395116,36,166,213,70,90,40,153,56,85,184,19,234,201,77,152,101,162,137,147,
10396133,91,129,62,132,148,218,48,219,69,19,39,6,234,5,100,234,201,77,156,109,
10397162,137,147,131,117,2,178,116,36,166,209,197,218,40,153,59,68,117,179,234,
10398201,78,32,11,180,81,50,118,136,235,103,208,146,156,72,21,104,162,100,226,
1039927,62,172,148,226,128,171,69,19,39,16,217,244,36,167,22,53,59,22,53,91,0,2,
1040021,11,94,181,128,196,133,0,185,80,32,56,156,199,130,36,160,72,16,78,126,53,
10401144,5,146,208,34,82,72,1,109,20,76,155,40,32,233,0,115,70,130,8,209,56,104,
10402105,187,252,193,3,17,162,112,201,242,18,65,211,0,230,149,132,17,162,112,
10403208,211,119,248,0,82,130,96,95,127,128,130,80,102,186,36,232,92,206,255,1,
1040480,48,200,39,12,158,241,64,
10405};
10406#else
10407#error invalid endianness defines
10408#endif
10409#endif /* DUK_USE_ROM_OBJECTS */
10410/*
10411 * Error and fatal handling.
10412 */
10413
10414/* #include duk_internal.h -> already included */
10415
10416#define DUK__ERRFMT_BUFSIZE 256 /* size for formatting buffers */
10417
10418#if defined(DUK_USE_VERBOSE_ERRORS)
10419
10420DUK_INTERNAL void duk_err_handle_error_fmt(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *fmt, ...) {
10421 va_list ap;
10422 char msg[DUK__ERRFMT_BUFSIZE];
10423 va_start(ap, fmt);
10424 (void) DUK_VSNPRINTF(msg, sizeof(msg), fmt, ap);
10425 msg[sizeof(msg) - 1] = (char) 0;
10426 duk_err_create_and_throw(thr, (duk_errcode_t) (line_and_code >> 24), msg, filename, (duk_int_t) (line_and_code & 0x00ffffffL));
10427 va_end(ap); /* dead code, but ensures portability (see Linux man page notes) */
10428}
10429
10430DUK_INTERNAL void duk_err_handle_error(duk_hthread *thr, const char *filename, duk_uint_t line_and_code, const char *msg) {
10431 duk_err_create_and_throw(thr, (duk_errcode_t) (line_and_code >> 24), msg, filename, (duk_int_t) (line_and_code & 0x00ffffffL));
10432}
10433
10434#else /* DUK_USE_VERBOSE_ERRORS */
10435
10436DUK_INTERNAL void duk_err_handle_error(duk_hthread *thr, duk_errcode_t code) {
10437 duk_err_create_and_throw(thr, code);
10438}
10439
10440#endif /* DUK_USE_VERBOSE_ERRORS */
10441
10442/*
10443 * Error throwing helpers
10444 */
10445
10446#if defined(DUK_USE_VERBOSE_ERRORS)
10447#if defined(DUK_USE_PARANOID_ERRORS)
10448DUK_INTERNAL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name) {
10449 DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)",
10450 expect_name, duk_get_type_name((duk_context *) thr, idx), (long) idx);
10451}
10452#else
10453DUK_INTERNAL void duk_err_require_type_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx, const char *expect_name) {
10454 DUK_ERROR_RAW_FMT3(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, "%s required, found %s (stack index %ld)",
10455 expect_name, duk_push_string_readable((duk_context *) thr, idx), (long) idx);
10456}
10457#endif
10458DUK_INTERNAL void duk_err_error_internal(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
10459 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ERROR, DUK_STR_INTERNAL_ERROR);
10460}
10461DUK_INTERNAL void duk_err_error_alloc_failed(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
10462 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ERROR, DUK_STR_ALLOC_FAILED);
10463}
10464DUK_INTERNAL void duk_err_error(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
10465 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_ERROR, message);
10466}
10467DUK_INTERNAL void duk_err_range(duk_hthread *thr, const char *filename, duk_int_t linenumber, const char *message) {
10468 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, message);
10469}
10470DUK_INTERNAL void duk_err_range_index(duk_hthread *thr, const char *filename, duk_int_t linenumber, duk_idx_t idx) {
10471 DUK_ERROR_RAW_FMT1(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, "invalid stack index %ld", (long) (idx));
10472}
10473DUK_INTERNAL void duk_err_range_push_beyond(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
10474 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_RANGE_ERROR, DUK_STR_PUSH_BEYOND_ALLOC_STACK);
10475}
10476DUK_INTERNAL void duk_err_type_invalid_args(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
10477 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_ARGS);
10478}
10479DUK_INTERNAL void duk_err_type_invalid_state(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
10480 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_STATE);
10481}
10482DUK_INTERNAL void duk_err_type_invalid_trap_result(duk_hthread *thr, const char *filename, duk_int_t linenumber) {
10483 DUK_ERROR_RAW(thr, filename, linenumber, DUK_ERR_TYPE_ERROR, DUK_STR_INVALID_TRAP_RESULT);
10484}
10485#else
10486/* The file/line arguments are NULL and 0, they're ignored by DUK_ERROR_RAW()
10487 * when non-verbose errors are used.
10488 */
10489
10490DUK_NORETURN(DUK_LOCAL_DECL void duk__err_shared(duk_hthread *thr, duk_uint_t code));
10491DUK_LOCAL void duk__err_shared(duk_hthread *thr, duk_uint_t code) {
10492 DUK_ERROR_RAW(thr, NULL, 0, code, NULL);
10493}
10494DUK_INTERNAL void duk_err_error(duk_hthread *thr) {
10495 duk__err_shared(thr, DUK_ERR_ERROR);
10496}
10497DUK_INTERNAL void duk_err_range(duk_hthread *thr) {
10498 duk__err_shared(thr, DUK_ERR_RANGE_ERROR);
10499}
10500DUK_INTERNAL void duk_err_eval(duk_hthread *thr) {
10501 duk__err_shared(thr, DUK_ERR_EVAL_ERROR);
10502}
10503DUK_INTERNAL void duk_err_reference(duk_hthread *thr) {
10504 duk__err_shared(thr, DUK_ERR_REFERENCE_ERROR);
10505}
10506DUK_INTERNAL void duk_err_syntax(duk_hthread *thr) {
10507 duk__err_shared(thr, DUK_ERR_SYNTAX_ERROR);
10508}
10509DUK_INTERNAL void duk_err_type(duk_hthread *thr) {
10510 duk__err_shared(thr, DUK_ERR_TYPE_ERROR);
10511}
10512DUK_INTERNAL void duk_err_uri(duk_hthread *thr) {
10513 duk__err_shared(thr, DUK_ERR_URI_ERROR);
10514}
10515#endif
10516
10517/*
10518 * Default fatal error handler
10519 */
10520
10521DUK_INTERNAL void duk_default_fatal_handler(void *udata, const char *msg) {
10522 DUK_UNREF(udata);
10523 DUK_UNREF(msg);
10524
10525#if defined(DUK_USE_FATAL_HANDLER)
10526 /* duk_config.h provided a custom default fatal handler. */
10527 DUK_D(DUK_DPRINT("custom default fatal error handler called: %s", msg ? msg : "NULL"));
10528 DUK_USE_FATAL_HANDLER(udata, msg);
10529#else
10530 /* Default behavior is to abort() on error. There's no printout
10531 * which makes this awkward, so it's always recommended to use an
10532 * explicit fatal error handler.
10533 */
10534 DUK_D(DUK_DPRINT("built-in default fatal error handler called: %s", msg ? msg : "NULL"));
10535 DUK_ABORT();
10536#endif
10537
10538 DUK_D(DUK_DPRINT("fatal error handler returned, enter forever loop"));
10539 for (;;) {
10540 /* Loop forever to ensure we don't return. */
10541 }
10542}
10543
10544/* automatic undefs */
10545#undef DUK__ERRFMT_BUFSIZE
10546/*
10547 * Various Unicode help functions for character classification predicates,
10548 * case conversion, decoding, etc.
10549 */
10550
10551/* #include duk_internal.h -> already included */
10552
10553/*
10554 * Fast path tables
10555 */
10556
10557#if defined(DUK_USE_IDCHAR_FASTPATH)
10558DUK_INTERNAL const duk_int8_t duk_is_idchar_tab[128] = {
10559 /* 0: not IdentifierStart or IdentifierPart
10560 * 1: IdentifierStart and IdentifierPart
10561 * -1: IdentifierPart only
10562 */
10563 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00...0x0f */
10564 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10...0x1f */
10565 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20...0x2f */
10566 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0, /* 0x30...0x3f */
10567 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x40...0x4f */
10568 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 0x50...0x5f */
10569 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x60...0x6f */
10570 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 /* 0x70...0x7f */
10571};
10572#endif
10573
10574/*
10575 * XUTF-8 and CESU-8 encoding/decoding
10576 */
10577
10578DUK_INTERNAL duk_small_int_t duk_unicode_get_xutf8_length(duk_ucodepoint_t cp) {
10579 duk_uint_fast32_t x = (duk_uint_fast32_t) cp;
10580 if (x < 0x80UL) {
10581 /* 7 bits */
10582 return 1;
10583 } else if (x < 0x800UL) {
10584 /* 11 bits */
10585 return 2;
10586 } else if (x < 0x10000UL) {
10587 /* 16 bits */
10588 return 3;
10589 } else if (x < 0x200000UL) {
10590 /* 21 bits */
10591 return 4;
10592 } else if (x < 0x4000000UL) {
10593 /* 26 bits */
10594 return 5;
10595 } else if (x < (duk_ucodepoint_t) 0x80000000UL) {
10596 /* 31 bits */
10597 return 6;
10598 } else {
10599 /* 36 bits */
10600 return 7;
10601 }
10602}
10603
10604#if defined(DUK_USE_ASSERTIONS)
10605DUK_INTERNAL duk_small_int_t duk_unicode_get_cesu8_length(duk_ucodepoint_t cp) {
10606 duk_uint_fast32_t x = (duk_uint_fast32_t) cp;
10607 if (x < 0x80UL) {
10608 /* 7 bits */
10609 return 1;
10610 } else if (x < 0x800UL) {
10611 /* 11 bits */
10612 return 2;
10613 } else if (x < 0x10000UL) {
10614 /* 16 bits */
10615 return 3;
10616 } else {
10617 /* Encoded as surrogate pair, each encoding to 3 bytes for
10618 * 6 bytes total. Codepoints above U+10FFFF encode as 6 bytes
10619 * too, see duk_unicode_encode_cesu8().
10620 */
10621 return 3 + 3;
10622 }
10623}
10624#endif /* DUK_USE_ASSERTIONS */
10625
10626DUK_INTERNAL const duk_uint8_t duk_unicode_xutf8_markers[7] = {
10627 0x00, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe
10628};
10629
10630/* Encode to extended UTF-8; 'out' must have space for at least
10631 * DUK_UNICODE_MAX_XUTF8_LENGTH bytes. Allows encoding of any
10632 * 32-bit (unsigned) codepoint.
10633 */
10634DUK_INTERNAL duk_small_int_t duk_unicode_encode_xutf8(duk_ucodepoint_t cp, duk_uint8_t *out) {
10635 duk_uint_fast32_t x = (duk_uint_fast32_t) cp;
10636 duk_small_int_t len;
10637 duk_uint8_t marker;
10638 duk_small_int_t i;
10639
10640 len = duk_unicode_get_xutf8_length(cp);
10641 DUK_ASSERT(len > 0);
10642
10643 marker = duk_unicode_xutf8_markers[len - 1]; /* 64-bit OK because always >= 0 */
10644
10645 i = len;
10646 DUK_ASSERT(i > 0);
10647 do {
10648 i--;
10649 if (i > 0) {
10650 out[i] = (duk_uint8_t) (0x80 + (x & 0x3f));
10651 x >>= 6;
10652 } else {
10653 /* Note: masking of 'x' is not necessary because of
10654 * range check and shifting -> no bits overlapping
10655 * the marker should be set.
10656 */
10657 out[0] = (duk_uint8_t) (marker + x);
10658 }
10659 } while (i > 0);
10660
10661 return len;
10662}
10663
10664/* Encode to CESU-8; 'out' must have space for at least
10665 * DUK_UNICODE_MAX_CESU8_LENGTH bytes; codepoints above U+10FFFF
10666 * will encode to garbage but won't overwrite the output buffer.
10667 */
10668DUK_INTERNAL duk_small_int_t duk_unicode_encode_cesu8(duk_ucodepoint_t cp, duk_uint8_t *out) {
10669 duk_uint_fast32_t x = (duk_uint_fast32_t) cp;
10670 duk_small_int_t len;
10671
10672 if (x < 0x80UL) {
10673 out[0] = (duk_uint8_t) x;
10674 len = 1;
10675 } else if (x < 0x800UL) {
10676 out[0] = (duk_uint8_t) (0xc0 + ((x >> 6) & 0x1f));
10677 out[1] = (duk_uint8_t) (0x80 + (x & 0x3f));
10678 len = 2;
10679 } else if (x < 0x10000UL) {
10680 /* surrogate pairs get encoded here */
10681 out[0] = (duk_uint8_t) (0xe0 + ((x >> 12) & 0x0f));
10682 out[1] = (duk_uint8_t) (0x80 + ((x >> 6) & 0x3f));
10683 out[2] = (duk_uint8_t) (0x80 + (x & 0x3f));
10684 len = 3;
10685 } else {
10686 /*
10687 * Unicode codepoints above U+FFFF are encoded as surrogate
10688 * pairs here. This ensures that all CESU-8 codepoints are
10689 * 16-bit values as expected in Ecmascript. The surrogate
10690 * pairs always get a 3-byte encoding (each) in CESU-8.
10691 * See: http://en.wikipedia.org/wiki/Surrogate_pair
10692 *
10693 * 20-bit codepoint, 10 bits (A and B) per surrogate pair:
10694 *
10695 * x = 0b00000000 0000AAAA AAAAAABB BBBBBBBB
10696 * sp1 = 0b110110AA AAAAAAAA (0xd800 + ((x >> 10) & 0x3ff))
10697 * sp2 = 0b110111BB BBBBBBBB (0xdc00 + (x & 0x3ff))
10698 *
10699 * Encoded into CESU-8:
10700 *
10701 * sp1 -> 0b11101101 (0xe0 + ((sp1 >> 12) & 0x0f))
10702 * -> 0b1010AAAA (0x80 + ((sp1 >> 6) & 0x3f))
10703 * -> 0b10AAAAAA (0x80 + (sp1 & 0x3f))
10704 * sp2 -> 0b11101101 (0xe0 + ((sp2 >> 12) & 0x0f))
10705 * -> 0b1011BBBB (0x80 + ((sp2 >> 6) & 0x3f))
10706 * -> 0b10BBBBBB (0x80 + (sp2 & 0x3f))
10707 *
10708 * Note that 0x10000 must be subtracted first. The code below
10709 * avoids the sp1, sp2 temporaries which saves around 20 bytes
10710 * of code.
10711 */
10712
10713 x -= 0x10000UL;
10714
10715 out[0] = (duk_uint8_t) (0xed);
10716 out[1] = (duk_uint8_t) (0xa0 + ((x >> 16) & 0x0f));
10717 out[2] = (duk_uint8_t) (0x80 + ((x >> 10) & 0x3f));
10718 out[3] = (duk_uint8_t) (0xed);
10719 out[4] = (duk_uint8_t) (0xb0 + ((x >> 6) & 0x0f));
10720 out[5] = (duk_uint8_t) (0x80 + (x & 0x3f));
10721 len = 6;
10722 }
10723
10724 return len;
10725}
10726
10727/* Decode helper. Return zero on error. */
10728DUK_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) {
10729 const duk_uint8_t *p;
10730 duk_uint32_t res;
10731 duk_uint_fast8_t ch;
10732 duk_small_int_t n;
10733
10734 DUK_UNREF(thr);
10735
10736 p = *ptr;
10737 if (p < ptr_start || p >= ptr_end) {
10738 goto fail;
10739 }
10740
10741 /*
10742 * UTF-8 decoder which accepts longer than standard byte sequences.
10743 * This allows full 32-bit code points to be used.
10744 */
10745
10746 ch = (duk_uint_fast8_t) (*p++);
10747 if (ch < 0x80) {
10748 /* 0xxx xxxx [7 bits] */
10749 res = (duk_uint32_t) (ch & 0x7f);
10750 n = 0;
10751 } else if (ch < 0xc0) {
10752 /* 10xx xxxx -> invalid */
10753 goto fail;
10754 } else if (ch < 0xe0) {
10755 /* 110x xxxx 10xx xxxx [11 bits] */
10756 res = (duk_uint32_t) (ch & 0x1f);
10757 n = 1;
10758 } else if (ch < 0xf0) {
10759 /* 1110 xxxx 10xx xxxx 10xx xxxx [16 bits] */
10760 res = (duk_uint32_t) (ch & 0x0f);
10761 n = 2;
10762 } else if (ch < 0xf8) {
10763 /* 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx [21 bits] */
10764 res = (duk_uint32_t) (ch & 0x07);
10765 n = 3;
10766 } else if (ch < 0xfc) {
10767 /* 1111 10xx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [26 bits] */
10768 res = (duk_uint32_t) (ch & 0x03);
10769 n = 4;
10770 } else if (ch < 0xfe) {
10771 /* 1111 110x 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [31 bits] */
10772 res = (duk_uint32_t) (ch & 0x01);
10773 n = 5;
10774 } else if (ch < 0xff) {
10775 /* 1111 1110 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [36 bits] */
10776 res = (duk_uint32_t) (0);
10777 n = 6;
10778 } else {
10779 /* 8-byte format could be:
10780 * 1111 1111 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx [41 bits]
10781 *
10782 * However, this format would not have a zero bit following the
10783 * leading one bits and would not allow 0xFF to be used as an
10784 * "invalid xutf-8" marker for internal keys. Further, 8-byte
10785 * encodings (up to 41 bit code points) are not currently needed.
10786 */
10787 goto fail;
10788 }
10789
10790 DUK_ASSERT(p >= ptr_start); /* verified at beginning */
10791 if (p + n > ptr_end) {
10792 /* check pointer at end */
10793 goto fail;
10794 }
10795
10796 while (n > 0) {
10797 DUK_ASSERT(p >= ptr_start && p < ptr_end);
10798 ch = (duk_uint_fast8_t) (*p++);
10799#if 0
10800 if (ch & 0xc0 != 0x80) {
10801 /* not a continuation byte */
10802 p--;
10803 *ptr = p;
10804 *out_cp = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
10805 return 1;
10806 }
10807#endif
10808 res = (res << 6) + (duk_uint32_t) (ch & 0x3f);
10809 n--;
10810 }
10811
10812 *ptr = p;
10813 *out_cp = res;
10814 return 1;
10815
10816 fail:
10817 return 0;
10818}
10819
10820/* used by e.g. duk_regexp_executor.c, string built-ins */
10821DUK_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) {
10822 duk_ucodepoint_t cp;
10823
10824 if (duk_unicode_decode_xutf8(thr, ptr, ptr_start, ptr_end, &cp)) {
10825 return cp;
10826 }
10827 DUK_ERROR_INTERNAL(thr);
10828 DUK_UNREACHABLE();
10829 return 0;
10830}
10831
10832/* Compute (extended) utf-8 length without codepoint encoding validation,
10833 * used for string interning.
10834 *
10835 * NOTE: This algorithm is performance critical, more so than string hashing
10836 * in some cases. It is needed when interning a string and needs to scan
10837 * every byte of the string with no skipping. Having an ASCII fast path
10838 * is useful if possible in the algorithm. The current algorithms were
10839 * chosen from several variants, based on x64 gcc -O2 testing. See:
10840 * https://github.com/svaarala/duktape/pull/422
10841 *
10842 * NOTE: must match tools/dukutil.py:duk_unicode_unvalidated_utf8_length().
10843 */
10844
10845#if defined(DUK_USE_PREFER_SIZE)
10846/* Small variant; roughly 150 bytes smaller than the fast variant. */
10847DUK_INTERNAL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen) {
10848 const duk_uint8_t *p;
10849 const duk_uint8_t *p_end;
10850 duk_size_t ncont;
10851 duk_size_t clen;
10852
10853 p = data;
10854 p_end = data + blen;
10855 ncont = 0;
10856 while (p != p_end) {
10857 duk_uint8_t x;
10858 x = *p++;
10859 if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) {
10860 ncont++;
10861 }
10862 }
10863
10864 DUK_ASSERT(ncont <= blen);
10865 clen = blen - ncont;
10866 DUK_ASSERT(clen <= blen);
10867 return clen;
10868}
10869#else /* DUK_USE_PREFER_SIZE */
10870/* This seems like a good overall approach. Fast path for ASCII in 4 byte
10871 * blocks.
10872 */
10873DUK_INTERNAL duk_size_t duk_unicode_unvalidated_utf8_length(const duk_uint8_t *data, duk_size_t blen) {
10874 const duk_uint8_t *p;
10875 const duk_uint8_t *p_end;
10876 const duk_uint32_t *p32_end;
10877 const duk_uint32_t *p32;
10878 duk_size_t ncont;
10879 duk_size_t clen;
10880
10881 ncont = 0; /* number of continuation (non-initial) bytes in [0x80,0xbf] */
10882 p = data;
10883 p_end = data + blen;
10884 if (blen < 16) {
10885 goto skip_fastpath;
10886 }
10887
10888 /* Align 'p' to 4; the input data may have arbitrary alignment.
10889 * End of string check not needed because blen >= 16.
10890 */
10891 while (((duk_size_t) (const void *) p) & 0x03U) {
10892 duk_uint8_t x;
10893 x = *p++;
10894 if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) {
10895 ncont++;
10896 }
10897 }
10898
10899 /* Full, aligned 4-byte reads. */
10900 p32_end = (const duk_uint32_t *) (const void *) (p + ((duk_size_t) (p_end - p) & (duk_size_t) (~0x03)));
10901 p32 = (const duk_uint32_t *) (const void *) p;
10902 while (p32 != (const duk_uint32_t *) p32_end) {
10903 duk_uint32_t x;
10904 x = *p32++;
10905 if (DUK_LIKELY((x & 0x80808080UL) == 0)) {
10906 ; /* ASCII fast path */
10907 } else {
10908 /* Flip highest bit of each byte which changes
10909 * the bit pattern 10xxxxxx into 00xxxxxx which
10910 * allows an easy bit mask test.
10911 */
10912 x ^= 0x80808080UL;
10913 if (DUK_UNLIKELY(!(x & 0xc0000000UL))) {
10914 ncont++;
10915 }
10916 if (DUK_UNLIKELY(!(x & 0x00c00000UL))) {
10917 ncont++;
10918 }
10919 if (DUK_UNLIKELY(!(x & 0x0000c000UL))) {
10920 ncont++;
10921 }
10922 if (DUK_UNLIKELY(!(x & 0x000000c0UL))) {
10923 ncont++;
10924 }
10925 }
10926 }
10927 p = (const duk_uint8_t *) p32;
10928 /* Fall through to handle the rest. */
10929
10930 skip_fastpath:
10931 while (p != p_end) {
10932 duk_uint8_t x;
10933 x = *p++;
10934 if (DUK_UNLIKELY(x >= 0x80 && x <= 0xbf)) {
10935 ncont++;
10936 }
10937 }
10938
10939 DUK_ASSERT(ncont <= blen);
10940 clen = blen - ncont;
10941 DUK_ASSERT(clen <= blen);
10942 return clen;
10943}
10944#endif /* DUK_USE_PREFER_SIZE */
10945
10946/*
10947 * Unicode range matcher
10948 *
10949 * Matches a codepoint against a packed bitstream of character ranges.
10950 * Used for slow path Unicode matching.
10951 */
10952
10953/* Must match tools/extract_chars.py, generate_match_table3(). */
10954DUK_LOCAL duk_uint32_t duk__uni_decode_value(duk_bitdecoder_ctx *bd_ctx) {
10955 duk_uint32_t t;
10956
10957 t = (duk_uint32_t) duk_bd_decode(bd_ctx, 4);
10958 if (t <= 0x0eU) {
10959 return t;
10960 }
10961 t = (duk_uint32_t) duk_bd_decode(bd_ctx, 8);
10962 if (t <= 0xfdU) {
10963 return t + 0x0f;
10964 }
10965 if (t == 0xfeU) {
10966 t = (duk_uint32_t) duk_bd_decode(bd_ctx, 12);
10967 return t + 0x0fU + 0xfeU;
10968 } else {
10969 t = (duk_uint32_t) duk_bd_decode(bd_ctx, 24);
10970 return t + 0x0fU + 0xfeU + 0x1000UL;
10971 }
10972}
10973
10974DUK_LOCAL duk_small_int_t duk__uni_range_match(const duk_uint8_t *unitab, duk_size_t unilen, duk_codepoint_t cp) {
10975 duk_bitdecoder_ctx bd_ctx;
10976 duk_codepoint_t prev_re;
10977
10978 DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
10979 bd_ctx.data = (const duk_uint8_t *) unitab;
10980 bd_ctx.length = (duk_size_t) unilen;
10981
10982 prev_re = 0;
10983 for (;;) {
10984 duk_codepoint_t r1, r2;
10985 r1 = (duk_codepoint_t) duk__uni_decode_value(&bd_ctx);
10986 if (r1 == 0) {
10987 break;
10988 }
10989 r2 = (duk_codepoint_t) duk__uni_decode_value(&bd_ctx);
10990
10991 r1 = prev_re + r1;
10992 r2 = r1 + r2;
10993 prev_re = r2;
10994
10995 /* [r1,r2] is the range */
10996
10997 DUK_DDD(DUK_DDDPRINT("duk__uni_range_match: cp=%06lx range=[0x%06lx,0x%06lx]",
10998 (unsigned long) cp, (unsigned long) r1, (unsigned long) r2));
10999 if (cp >= r1 && cp <= r2) {
11000 return 1;
11001 }
11002 }
11003
11004 return 0;
11005}
11006
11007/*
11008 * "WhiteSpace" production check.
11009 */
11010
11011DUK_INTERNAL duk_small_int_t duk_unicode_is_whitespace(duk_codepoint_t cp) {
11012 /*
11013 * E5 Section 7.2 specifies six characters specifically as
11014 * white space:
11015 *
11016 * 0009;<control>;Cc;0;S;;;;;N;CHARACTER TABULATION;;;;
11017 * 000B;<control>;Cc;0;S;;;;;N;LINE TABULATION;;;;
11018 * 000C;<control>;Cc;0;WS;;;;;N;FORM FEED (FF);;;;
11019 * 0020;SPACE;Zs;0;WS;;;;;N;;;;;
11020 * 00A0;NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;NON-BREAKING SPACE;;;;
11021 * FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;;
11022 *
11023 * It also specifies any Unicode category 'Zs' characters as white
11024 * space. These can be extracted with the "tools/extract_chars.py" script.
11025 * Current result:
11026 *
11027 * RAW OUTPUT:
11028 * ===========
11029 * 0020;SPACE;Zs;0;WS;;;;;N;;;;;
11030 * 00A0;NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;NON-BREAKING SPACE;;;;
11031 * 1680;OGHAM SPACE MARK;Zs;0;WS;;;;;N;;;;;
11032 * 180E;MONGOLIAN VOWEL SEPARATOR;Zs;0;WS;;;;;N;;;;;
11033 * 2000;EN QUAD;Zs;0;WS;2002;;;;N;;;;;
11034 * 2001;EM QUAD;Zs;0;WS;2003;;;;N;;;;;
11035 * 2002;EN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
11036 * 2003;EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
11037 * 2004;THREE-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
11038 * 2005;FOUR-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
11039 * 2006;SIX-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
11040 * 2007;FIGURE SPACE;Zs;0;WS;<noBreak> 0020;;;;N;;;;;
11041 * 2008;PUNCTUATION SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
11042 * 2009;THIN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
11043 * 200A;HAIR SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
11044 * 202F;NARROW NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;;;;;
11045 * 205F;MEDIUM MATHEMATICAL SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
11046 * 3000;IDEOGRAPHIC SPACE;Zs;0;WS;<wide> 0020;;;;N;;;;;
11047 *
11048 * RANGES:
11049 * =======
11050 * 0x0020
11051 * 0x00a0
11052 * 0x1680
11053 * 0x180e
11054 * 0x2000 ... 0x200a
11055 * 0x202f
11056 * 0x205f
11057 * 0x3000
11058 *
11059 * A manual decoder (below) is probably most compact for this.
11060 */
11061
11062 duk_uint_fast8_t lo;
11063 duk_uint_fast32_t hi;
11064
11065 /* cp == -1 (EOF) never matches and causes return value 0 */
11066
11067 lo = (duk_uint_fast8_t) (cp & 0xff);
11068 hi = (duk_uint_fast32_t) (cp >> 8); /* does not fit into an uchar */
11069
11070 if (hi == 0x0000UL) {
11071 if (lo == 0x09U || lo == 0x0bU || lo == 0x0cU ||
11072 lo == 0x20U || lo == 0xa0U) {
11073 return 1;
11074 }
11075 } else if (hi == 0x0020UL) {
11076 if (lo <= 0x0aU || lo == 0x2fU || lo == 0x5fU) {
11077 return 1;
11078 }
11079 } else if (cp == 0x1680L || cp == 0x180eL || cp == 0x3000L ||
11080 cp == 0xfeffL) {
11081 return 1;
11082 }
11083
11084 return 0;
11085}
11086
11087/*
11088 * "LineTerminator" production check.
11089 */
11090
11091DUK_INTERNAL duk_small_int_t duk_unicode_is_line_terminator(duk_codepoint_t cp) {
11092 /*
11093 * E5 Section 7.3
11094 *
11095 * A LineTerminatorSequence essentially merges <CR> <LF> sequences
11096 * into a single line terminator. This must be handled by the caller.
11097 */
11098
11099 if (cp == 0x000aL || cp == 0x000dL || cp == 0x2028L ||
11100 cp == 0x2029L) {
11101 return 1;
11102 }
11103
11104 return 0;
11105}
11106
11107/*
11108 * "IdentifierStart" production check.
11109 */
11110
11111DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_start(duk_codepoint_t cp) {
11112 /*
11113 * E5 Section 7.6:
11114 *
11115 * IdentifierStart:
11116 * UnicodeLetter
11117 * $
11118 * _
11119 * \ UnicodeEscapeSequence
11120 *
11121 * IdentifierStart production has one multi-character production:
11122 *
11123 * \ UnicodeEscapeSequence
11124 *
11125 * The '\' character is -not- matched by this function. Rather, the caller
11126 * should decode the escape and then call this function to check whether the
11127 * decoded character is acceptable (see discussion in E5 Section 7.6).
11128 *
11129 * The "UnicodeLetter" alternative of the production allows letters
11130 * from various Unicode categories. These can be extracted with the
11131 * "tools/extract_chars.py" script.
11132 *
11133 * Because the result has hundreds of Unicode codepoint ranges, matching
11134 * for any values >= 0x80 are done using a very slow range-by-range scan
11135 * and a packed range format.
11136 *
11137 * The ASCII portion (codepoints 0x00 ... 0x7f) is fast-pathed below because
11138 * it matters the most. The ASCII related ranges of IdentifierStart are:
11139 *
11140 * 0x0041 ... 0x005a ['A' ... 'Z']
11141 * 0x0061 ... 0x007a ['a' ... 'z']
11142 * 0x0024 ['$']
11143 * 0x005f ['_']
11144 */
11145
11146 /* ASCII (and EOF) fast path -- quick accept and reject */
11147 if (cp <= 0x7fL) {
11148#if defined(DUK_USE_IDCHAR_FASTPATH)
11149 return (cp >= 0) && (duk_is_idchar_tab[cp] > 0);
11150#else
11151 if ((cp >= 'a' && cp <= 'z') ||
11152 (cp >= 'A' && cp <= 'Z') ||
11153 cp == '_' || cp == '$') {
11154 return 1;
11155 }
11156 return 0;
11157#endif
11158 }
11159
11160 /* Non-ASCII slow path (range-by-range linear comparison), very slow */
11161
11162#if defined(DUK_USE_SOURCE_NONBMP)
11163 if (duk__uni_range_match(duk_unicode_ids_noa,
11164 (duk_size_t) sizeof(duk_unicode_ids_noa),
11165 (duk_codepoint_t) cp)) {
11166 return 1;
11167 }
11168 return 0;
11169#else
11170 if (cp < 0x10000L) {
11171 if (duk__uni_range_match(duk_unicode_ids_noabmp,
11172 sizeof(duk_unicode_ids_noabmp),
11173 (duk_codepoint_t) cp)) {
11174 return 1;
11175 }
11176 return 0;
11177 } else {
11178 /* without explicit non-BMP support, assume non-BMP characters
11179 * are always accepted as identifier characters.
11180 */
11181 return 1;
11182 }
11183#endif
11184}
11185
11186/*
11187 * "IdentifierPart" production check.
11188 */
11189
11190DUK_INTERNAL duk_small_int_t duk_unicode_is_identifier_part(duk_codepoint_t cp) {
11191 /*
11192 * E5 Section 7.6:
11193 *
11194 * IdentifierPart:
11195 * IdentifierStart
11196 * UnicodeCombiningMark
11197 * UnicodeDigit
11198 * UnicodeConnectorPunctuation
11199 * <ZWNJ> [U+200C]
11200 * <ZWJ> [U+200D]
11201 *
11202 * IdentifierPart production has one multi-character production
11203 * as part of its IdentifierStart alternative. The '\' character
11204 * of an escape sequence is not matched here, see discussion in
11205 * duk_unicode_is_identifier_start().
11206 *
11207 * To match non-ASCII characters (codepoints >= 0x80), a very slow
11208 * linear range-by-range scan is used. The codepoint is first compared
11209 * to the IdentifierStart ranges, and if it doesn't match, then to a
11210 * set consisting of code points in IdentifierPart but not in
11211 * IdentifierStart. This is done to keep the unicode range data small,
11212 * at the expense of speed.
11213 *
11214 * The ASCII fast path consists of:
11215 *
11216 * 0x0030 ... 0x0039 ['0' ... '9', UnicodeDigit]
11217 * 0x0041 ... 0x005a ['A' ... 'Z', IdentifierStart]
11218 * 0x0061 ... 0x007a ['a' ... 'z', IdentifierStart]
11219 * 0x0024 ['$', IdentifierStart]
11220 * 0x005f ['_', IdentifierStart and
11221 * UnicodeConnectorPunctuation]
11222 *
11223 * UnicodeCombiningMark has no code points <= 0x7f.
11224 *
11225 * The matching code reuses the "identifier start" tables, and then
11226 * consults a separate range set for characters in "identifier part"
11227 * but not in "identifier start". These can be extracted with the
11228 * "tools/extract_chars.py" script.
11229 *
11230 * UnicodeCombiningMark -> categories Mn, Mc
11231 * UnicodeDigit -> categories Nd
11232 * UnicodeConnectorPunctuation -> categories Pc
11233 */
11234
11235 /* ASCII (and EOF) fast path -- quick accept and reject */
11236 if (cp <= 0x7fL) {
11237#if defined(DUK_USE_IDCHAR_FASTPATH)
11238 return (cp >= 0) && (duk_is_idchar_tab[cp] != 0);
11239#else
11240 if ((cp >= 'a' && cp <= 'z') ||
11241 (cp >= 'A' && cp <= 'Z') ||
11242 (cp >= '0' && cp <= '9') ||
11243 cp == '_' || cp == '$') {
11244 return 1;
11245 }
11246 return 0;
11247#endif
11248 }
11249
11250 /* Non-ASCII slow path (range-by-range linear comparison), very slow */
11251
11252#if defined(DUK_USE_SOURCE_NONBMP)
11253 if (duk__uni_range_match(duk_unicode_ids_noa,
11254 sizeof(duk_unicode_ids_noa),
11255 (duk_codepoint_t) cp) ||
11256 duk__uni_range_match(duk_unicode_idp_m_ids_noa,
11257 sizeof(duk_unicode_idp_m_ids_noa),
11258 (duk_codepoint_t) cp)) {
11259 return 1;
11260 }
11261 return 0;
11262#else
11263 if (cp < 0x10000L) {
11264 if (duk__uni_range_match(duk_unicode_ids_noabmp,
11265 sizeof(duk_unicode_ids_noabmp),
11266 (duk_codepoint_t) cp) ||
11267 duk__uni_range_match(duk_unicode_idp_m_ids_noabmp,
11268 sizeof(duk_unicode_idp_m_ids_noabmp),
11269 (duk_codepoint_t) cp)) {
11270 return 1;
11271 }
11272 return 0;
11273 } else {
11274 /* without explicit non-BMP support, assume non-BMP characters
11275 * are always accepted as identifier characters.
11276 */
11277 return 1;
11278 }
11279#endif
11280}
11281
11282/*
11283 * Unicode letter check.
11284 */
11285
11286DUK_INTERNAL duk_small_int_t duk_unicode_is_letter(duk_codepoint_t cp) {
11287 /*
11288 * Unicode letter is now taken to be the categories:
11289 *
11290 * Lu, Ll, Lt, Lm, Lo
11291 *
11292 * (Not sure if this is exactly correct.)
11293 *
11294 * The ASCII fast path consists of:
11295 *
11296 * 0x0041 ... 0x005a ['A' ... 'Z']
11297 * 0x0061 ... 0x007a ['a' ... 'z']
11298 */
11299
11300 /* ASCII (and EOF) fast path -- quick accept and reject */
11301 if (cp <= 0x7fL) {
11302 if ((cp >= 'a' && cp <= 'z') ||
11303 (cp >= 'A' && cp <= 'Z')) {
11304 return 1;
11305 }
11306 return 0;
11307 }
11308
11309 /* Non-ASCII slow path (range-by-range linear comparison), very slow */
11310
11311#if defined(DUK_USE_SOURCE_NONBMP)
11312 if (duk__uni_range_match(duk_unicode_ids_noa,
11313 sizeof(duk_unicode_ids_noa),
11314 (duk_codepoint_t) cp) &&
11315 !duk__uni_range_match(duk_unicode_ids_m_let_noa,
11316 sizeof(duk_unicode_ids_m_let_noa),
11317 (duk_codepoint_t) cp)) {
11318 return 1;
11319 }
11320 return 0;
11321#else
11322 if (cp < 0x10000L) {
11323 if (duk__uni_range_match(duk_unicode_ids_noabmp,
11324 sizeof(duk_unicode_ids_noabmp),
11325 (duk_codepoint_t) cp) &&
11326 !duk__uni_range_match(duk_unicode_ids_m_let_noabmp,
11327 sizeof(duk_unicode_ids_m_let_noabmp),
11328 (duk_codepoint_t) cp)) {
11329 return 1;
11330 }
11331 return 0;
11332 } else {
11333 /* without explicit non-BMP support, assume non-BMP characters
11334 * are always accepted as letters.
11335 */
11336 return 1;
11337 }
11338#endif
11339}
11340
11341/*
11342 * Complex case conversion helper which decodes a bit-packed conversion
11343 * control stream generated by tools/extract_caseconv.py. The conversion
11344 * is very slow because it runs through the conversion data in a linear
11345 * fashion to save space (which is why ASCII characters have a special
11346 * fast path before arriving here).
11347 *
11348 * The particular bit counts etc have been determined experimentally to
11349 * be small but still sufficient, and must match the Python script
11350 * (tools/extract_caseconv.py).
11351 *
11352 * The return value is the case converted codepoint or -1 if the conversion
11353 * results in multiple characters (this is useful for regexp Canonicalization
11354 * operation). If 'buf' is not NULL, the result codepoint(s) are also
11355 * appended to the hbuffer.
11356 *
11357 * Context and locale specific rules must be checked before consulting
11358 * this function.
11359 */
11360
11361DUK_LOCAL
11362duk_codepoint_t duk__slow_case_conversion(duk_hthread *thr,
11364 duk_codepoint_t cp,
11365 duk_bitdecoder_ctx *bd_ctx) {
11366 duk_small_int_t skip = 0;
11367 duk_small_int_t n;
11368 duk_small_int_t t;
11369 duk_small_int_t count;
11370 duk_codepoint_t tmp_cp;
11371 duk_codepoint_t start_i;
11372 duk_codepoint_t start_o;
11373
11374 DUK_UNREF(thr);
11375 DUK_ASSERT(bd_ctx != NULL);
11376
11377 DUK_DDD(DUK_DDDPRINT("slow case conversion for codepoint: %ld", (long) cp));
11378
11379 /* range conversion with a "skip" */
11380 DUK_DDD(DUK_DDDPRINT("checking ranges"));
11381 for (;;) {
11382 skip++;
11383 n = (duk_small_int_t) duk_bd_decode(bd_ctx, 6);
11384 if (n == 0x3f) {
11385 /* end marker */
11386 break;
11387 }
11388 DUK_DDD(DUK_DDDPRINT("skip=%ld, n=%ld", (long) skip, (long) n));
11389
11390 while (n--) {
11391 start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
11392 start_o = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
11393 count = (duk_small_int_t) duk_bd_decode(bd_ctx, 7);
11394 DUK_DDD(DUK_DDDPRINT("range: start_i=%ld, start_o=%ld, count=%ld, skip=%ld",
11395 (long) start_i, (long) start_o, (long) count, (long) skip));
11396
11397 if (cp >= start_i) {
11398 tmp_cp = cp - start_i; /* always >= 0 */
11399 if (tmp_cp < (duk_codepoint_t) count * (duk_codepoint_t) skip &&
11400 (tmp_cp % (duk_codepoint_t) skip) == 0) {
11401 DUK_DDD(DUK_DDDPRINT("range matches input codepoint"));
11402 cp = start_o + tmp_cp;
11403 goto single;
11404 }
11405 }
11406 }
11407 }
11408
11409 /* 1:1 conversion */
11410 n = (duk_small_int_t) duk_bd_decode(bd_ctx, 7);
11411 DUK_DDD(DUK_DDDPRINT("checking 1:1 conversions (count %ld)", (long) n));
11412 while (n--) {
11413 start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
11414 start_o = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
11415 DUK_DDD(DUK_DDDPRINT("1:1 conversion %ld -> %ld", (long) start_i, (long) start_o));
11416 if (cp == start_i) {
11417 DUK_DDD(DUK_DDDPRINT("1:1 matches input codepoint"));
11418 cp = start_o;
11419 goto single;
11420 }
11421 }
11422
11423 /* complex, multicharacter conversion */
11424 n = (duk_small_int_t) duk_bd_decode(bd_ctx, 7);
11425 DUK_DDD(DUK_DDDPRINT("checking 1:n conversions (count %ld)", (long) n));
11426 while (n--) {
11427 start_i = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
11428 t = (duk_small_int_t) duk_bd_decode(bd_ctx, 2);
11429 DUK_DDD(DUK_DDDPRINT("1:n conversion %ld -> %ld chars", (long) start_i, (long) t));
11430 if (cp == start_i) {
11431 DUK_DDD(DUK_DDDPRINT("1:n matches input codepoint"));
11432 if (bw != NULL) {
11433 while (t--) {
11434 tmp_cp = (duk_codepoint_t) duk_bd_decode(bd_ctx, 16);
11435 DUK_BW_WRITE_RAW_XUTF8(thr, bw, (duk_ucodepoint_t) tmp_cp);
11436 }
11437 }
11438 return -1;
11439 } else {
11440 while (t--) {
11441 (void) duk_bd_decode(bd_ctx, 16);
11442 }
11443 }
11444 }
11445
11446 /* default: no change */
11447 DUK_DDD(DUK_DDDPRINT("no rule matches, output is same as input"));
11448 /* fall through */
11449
11450 single:
11451 if (bw != NULL) {
11452 DUK_BW_WRITE_RAW_XUTF8(thr, bw, (duk_ucodepoint_t) cp);
11453 }
11454 return cp;
11455}
11456
11457/*
11458 * Case conversion helper, with context/local sensitivity.
11459 * For proper case conversion, one needs to know the character
11460 * and the preceding and following characters, as well as
11461 * locale/language.
11462 */
11463
11464/* XXX: add 'language' argument when locale/language sensitive rule
11465 * support added.
11466 */
11467DUK_LOCAL
11468duk_codepoint_t duk__case_transform_helper(duk_hthread *thr,
11470 duk_codepoint_t cp,
11471 duk_codepoint_t prev,
11472 duk_codepoint_t next,
11473 duk_bool_t uppercase) {
11474 duk_bitdecoder_ctx bd_ctx;
11475
11476 /* fast path for ASCII */
11477 if (cp < 0x80L) {
11478 /* XXX: there are language sensitive rules for the ASCII range.
11479 * If/when language/locale support is implemented, they need to
11480 * be implemented here for the fast path. There are no context
11481 * sensitive rules for ASCII range.
11482 */
11483
11484 if (uppercase) {
11485 if (cp >= 'a' && cp <= 'z') {
11486 cp = cp - 'a' + 'A';
11487 }
11488 } else {
11489 if (cp >= 'A' && cp <= 'Z') {
11490 cp = cp - 'A' + 'a';
11491 }
11492 }
11493
11494 if (bw != NULL) {
11495 DUK_BW_WRITE_RAW_U8(thr, bw, (duk_uint8_t) cp);
11496 }
11497 return cp;
11498 }
11499
11500 /* context and locale specific rules which cannot currently be represented
11501 * in the caseconv bitstream: hardcoded rules in C
11502 */
11503 if (uppercase) {
11504 /* XXX: turkish / azeri */
11505 } else {
11506 /*
11507 * Final sigma context specific rule. This is a rather tricky
11508 * rule and this handling is probably not 100% correct now.
11509 * The rule is not locale/language specific so it is supported.
11510 */
11511
11512 if (cp == 0x03a3L && /* U+03A3 = GREEK CAPITAL LETTER SIGMA */
11513 duk_unicode_is_letter(prev) && /* prev exists and is not a letter */
11514 !duk_unicode_is_letter(next)) { /* next does not exist or next is not a letter */
11515 /* Capital sigma occurred at "end of word", lowercase to
11516 * U+03C2 = GREEK SMALL LETTER FINAL SIGMA. Otherwise
11517 * fall through and let the normal rules lowercase it to
11518 * U+03C3 = GREEK SMALL LETTER SIGMA.
11519 */
11520 cp = 0x03c2L;
11521 goto singlechar;
11522 }
11523
11524 /* XXX: lithuanian not implemented */
11525 /* XXX: lithuanian, explicit dot rules */
11526 /* XXX: turkish / azeri, lowercase rules */
11527 }
11528
11529 /* 1:1 or special conversions, but not locale/context specific: script generated rules */
11530 DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
11531 if (uppercase) {
11532 bd_ctx.data = (const duk_uint8_t *) duk_unicode_caseconv_uc;
11533 bd_ctx.length = (duk_size_t) sizeof(duk_unicode_caseconv_uc);
11534 } else {
11535 bd_ctx.data = (const duk_uint8_t *) duk_unicode_caseconv_lc;
11536 bd_ctx.length = (duk_size_t) sizeof(duk_unicode_caseconv_lc);
11537 }
11538 return duk__slow_case_conversion(thr, bw, cp, &bd_ctx);
11539
11540 singlechar:
11541 if (bw != NULL) {
11542 DUK_BW_WRITE_RAW_XUTF8(thr, bw, (duk_ucodepoint_t) cp);
11543 }
11544 return cp;
11545
11546 /* unused now, not needed until Turkish/Azeri */
11547#if 0
11548 nochar:
11549 return -1;
11550#endif
11551}
11552
11553/*
11554 * Replace valstack top with case converted version.
11555 */
11556
11557DUK_INTERNAL void duk_unicode_case_convert_string(duk_hthread *thr, duk_small_int_t uppercase) {
11558 duk_context *ctx = (duk_context *) thr;
11559 duk_hstring *h_input;
11560 duk_bufwriter_ctx bw_alloc;
11562 const duk_uint8_t *p, *p_start, *p_end;
11563 duk_codepoint_t prev, curr, next;
11564
11565 h_input = duk_require_hstring(ctx, -1); /* Accept symbols. */
11566 DUK_ASSERT(h_input != NULL);
11567
11568 bw = &bw_alloc;
11569 DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input));
11570
11571 /* [ ... input buffer ] */
11572
11573 p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
11574 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
11575 p = p_start;
11576
11577 prev = -1; DUK_UNREF(prev);
11578 curr = -1;
11579 next = -1;
11580 for (;;) {
11581 prev = curr;
11582 curr = next;
11583 next = -1;
11584 if (p < p_end) {
11585 next = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
11586 } else {
11587 /* end of input and last char has been processed */
11588 if (curr < 0) {
11589 break;
11590 }
11591 }
11592
11593 /* on first round, skip */
11594 if (curr >= 0) {
11595 /* XXX: could add a fast path to process chunks of input codepoints,
11596 * but relative benefit would be quite small.
11597 */
11598
11599 /* Ensure space for maximum multi-character result; estimate is overkill. */
11600 DUK_BW_ENSURE(thr, bw, 8 * DUK_UNICODE_MAX_XUTF8_LENGTH);
11601
11602 duk__case_transform_helper(thr,
11603 bw,
11604 (duk_codepoint_t) curr,
11605 prev,
11606 next,
11607 uppercase);
11608 }
11609 }
11610
11611 DUK_BW_COMPACT(thr, bw);
11612 (void) duk_buffer_to_string(ctx, -1); /* Safe, output is encoded. */
11613 /* invalidates h_buf pointer */
11614 duk_remove_m2(ctx);
11615}
11616
11617#if defined(DUK_USE_REGEXP_SUPPORT)
11618
11619/*
11620 * Canonicalize() abstract operation needed for canonicalization of individual
11621 * codepoints during regexp compilation and execution, see E5 Section 15.10.2.8.
11622 * Note that codepoints are canonicalized one character at a time, so no context
11623 * specific rules can apply. Locale specific rules can apply, though.
11624 */
11625
11626DUK_INTERNAL duk_codepoint_t duk_unicode_re_canonicalize_char(duk_hthread *thr, duk_codepoint_t cp) {
11627#if defined(DUK_USE_REGEXP_CANON_WORKAROUND)
11628 /* Fast canonicalization lookup at the cost of 128kB footprint. */
11629 DUK_ASSERT(cp >= 0);
11630 DUK_UNREF(thr);
11631 if (DUK_LIKELY(cp < 0x10000L)) {
11632 return (duk_codepoint_t) duk_unicode_re_canon_lookup[cp];
11633 }
11634 return cp;
11635#else /* DUK_USE_REGEXP_CANON_WORKAROUND */
11636 duk_codepoint_t y;
11637
11638 y = duk__case_transform_helper(thr,
11639 NULL, /* NULL is allowed, no output */
11640 cp, /* curr char */
11641 -1, /* prev char */
11642 -1, /* next char */
11643 1); /* uppercase */
11644
11645 if ((y < 0) || (cp >= 0x80 && y < 0x80)) {
11646 /* multiple codepoint conversion or non-ASCII mapped to ASCII
11647 * --> leave as is.
11648 */
11649 return cp;
11650 }
11651
11652 return y;
11653#endif /* DUK_USE_REGEXP_CANON_WORKAROUND */
11654}
11655
11656/*
11657 * E5 Section 15.10.2.6 "IsWordChar" abstract operation. Assume
11658 * x < 0 for characters read outside the string.
11659 */
11660
11661DUK_INTERNAL duk_small_int_t duk_unicode_re_is_wordchar(duk_codepoint_t x) {
11662 /*
11663 * Note: the description in E5 Section 15.10.2.6 has a typo, it
11664 * contains 'A' twice and lacks 'a'; the intent is [0-9a-zA-Z_].
11665 */
11666 if ((x >= '0' && x <= '9') ||
11667 (x >= 'a' && x <= 'z') ||
11668 (x >= 'A' && x <= 'Z') ||
11669 (x == '_')) {
11670 return 1;
11671 }
11672 return 0;
11673}
11674
11675/*
11676 * Regexp range tables
11677 */
11678
11679/* exposed because lexer needs these too */
11680DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_digit[2] = {
11681 (duk_uint16_t) 0x0030UL, (duk_uint16_t) 0x0039UL,
11682};
11683DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_white[22] = {
11684 (duk_uint16_t) 0x0009UL, (duk_uint16_t) 0x000DUL,
11685 (duk_uint16_t) 0x0020UL, (duk_uint16_t) 0x0020UL,
11686 (duk_uint16_t) 0x00A0UL, (duk_uint16_t) 0x00A0UL,
11687 (duk_uint16_t) 0x1680UL, (duk_uint16_t) 0x1680UL,
11688 (duk_uint16_t) 0x180EUL, (duk_uint16_t) 0x180EUL,
11689 (duk_uint16_t) 0x2000UL, (duk_uint16_t) 0x200AUL,
11690 (duk_uint16_t) 0x2028UL, (duk_uint16_t) 0x2029UL,
11691 (duk_uint16_t) 0x202FUL, (duk_uint16_t) 0x202FUL,
11692 (duk_uint16_t) 0x205FUL, (duk_uint16_t) 0x205FUL,
11693 (duk_uint16_t) 0x3000UL, (duk_uint16_t) 0x3000UL,
11694 (duk_uint16_t) 0xFEFFUL, (duk_uint16_t) 0xFEFFUL,
11695};
11696DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_wordchar[8] = {
11697 (duk_uint16_t) 0x0030UL, (duk_uint16_t) 0x0039UL,
11698 (duk_uint16_t) 0x0041UL, (duk_uint16_t) 0x005AUL,
11699 (duk_uint16_t) 0x005FUL, (duk_uint16_t) 0x005FUL,
11700 (duk_uint16_t) 0x0061UL, (duk_uint16_t) 0x007AUL,
11701};
11702DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_digit[4] = {
11703 (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x002FUL,
11704 (duk_uint16_t) 0x003AUL, (duk_uint16_t) 0xFFFFUL,
11705};
11706DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_white[24] = {
11707 (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x0008UL,
11708 (duk_uint16_t) 0x000EUL, (duk_uint16_t) 0x001FUL,
11709 (duk_uint16_t) 0x0021UL, (duk_uint16_t) 0x009FUL,
11710 (duk_uint16_t) 0x00A1UL, (duk_uint16_t) 0x167FUL,
11711 (duk_uint16_t) 0x1681UL, (duk_uint16_t) 0x180DUL,
11712 (duk_uint16_t) 0x180FUL, (duk_uint16_t) 0x1FFFUL,
11713 (duk_uint16_t) 0x200BUL, (duk_uint16_t) 0x2027UL,
11714 (duk_uint16_t) 0x202AUL, (duk_uint16_t) 0x202EUL,
11715 (duk_uint16_t) 0x2030UL, (duk_uint16_t) 0x205EUL,
11716 (duk_uint16_t) 0x2060UL, (duk_uint16_t) 0x2FFFUL,
11717 (duk_uint16_t) 0x3001UL, (duk_uint16_t) 0xFEFEUL,
11718 (duk_uint16_t) 0xFF00UL, (duk_uint16_t) 0xFFFFUL,
11719};
11720DUK_INTERNAL const duk_uint16_t duk_unicode_re_ranges_not_wordchar[10] = {
11721 (duk_uint16_t) 0x0000UL, (duk_uint16_t) 0x002FUL,
11722 (duk_uint16_t) 0x003AUL, (duk_uint16_t) 0x0040UL,
11723 (duk_uint16_t) 0x005BUL, (duk_uint16_t) 0x005EUL,
11724 (duk_uint16_t) 0x0060UL, (duk_uint16_t) 0x0060UL,
11725 (duk_uint16_t) 0x007BUL, (duk_uint16_t) 0xFFFFUL,
11726};
11727
11728#endif /* DUK_USE_REGEXP_SUPPORT */
11729/*
11730 * Misc util stuff
11731 */
11732
11733/* #include duk_internal.h -> already included */
11734
11735/*
11736 * Lowercase digits for radix values 2 to 36. Also doubles as lowercase
11737 * hex nybble table.
11738 */
11739
11740DUK_INTERNAL const duk_uint8_t duk_lc_digits[36] = {
11741 DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3,
11742 DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7,
11743 DUK_ASC_8, DUK_ASC_9, DUK_ASC_LC_A, DUK_ASC_LC_B,
11744 DUK_ASC_LC_C, DUK_ASC_LC_D, DUK_ASC_LC_E, DUK_ASC_LC_F,
11745 DUK_ASC_LC_G, DUK_ASC_LC_H, DUK_ASC_LC_I, DUK_ASC_LC_J,
11746 DUK_ASC_LC_K, DUK_ASC_LC_L, DUK_ASC_LC_M, DUK_ASC_LC_N,
11747 DUK_ASC_LC_O, DUK_ASC_LC_P, DUK_ASC_LC_Q, DUK_ASC_LC_R,
11748 DUK_ASC_LC_S, DUK_ASC_LC_T, DUK_ASC_LC_U, DUK_ASC_LC_V,
11749 DUK_ASC_LC_W, DUK_ASC_LC_X, DUK_ASC_LC_Y, DUK_ASC_LC_Z
11750};
11751
11752DUK_INTERNAL const duk_uint8_t duk_uc_nybbles[16] = {
11753 DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3,
11754 DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7,
11755 DUK_ASC_8, DUK_ASC_9, DUK_ASC_UC_A, DUK_ASC_UC_B,
11756 DUK_ASC_UC_C, DUK_ASC_UC_D, DUK_ASC_UC_E, DUK_ASC_UC_F
11757};
11758
11759/*
11760 * Table for hex decoding ASCII hex digits
11761 */
11762
11763DUK_INTERNAL const duk_int8_t duk_hex_dectab[256] = {
11764 /* -1 if invalid */
11765 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0f */
11766 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1f */
11767 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x20-0x2f */
11768 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0x30-0x3f */
11769 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x40-0x4f */
11770 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x50-0x5f */
11771 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x60-0x6f */
11772 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x70-0x7f */
11773 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80-0x8f */
11774 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90-0x9f */
11775 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0-0xaf */
11776 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0-0xbf */
11777 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0-0xcf */
11778 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0-0xdf */
11779 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0-0xef */
11780 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0-0xff */
11781};
11782
11783#if defined(DUK_USE_HEX_FASTPATH)
11784/* Preshifted << 4. Must use 16-bit entry to allow negative value signaling. */
11785DUK_INTERNAL const duk_int16_t duk_hex_dectab_shift4[256] = {
11786 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00-0x0f */
11787 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10-0x1f */
11788 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x20-0x2f */
11789 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, -1, -1, -1, -1, -1, -1, /* 0x30-0x3f */
11790 -1, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x40-0x4f */
11791 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x50-0x5f */
11792 -1, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x60-0x6f */
11793 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x70-0x7f */
11794 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80-0x8f */
11795 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90-0x9f */
11796 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0-0xaf */
11797 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0-0xbf */
11798 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0-0xcf */
11799 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0-0xdf */
11800 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0-0xef */
11801 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0-0xff */
11802};
11803#endif
11804
11805/*
11806 * Table for hex encoding bytes
11807 */
11808
11809#if defined(DUK_USE_HEX_FASTPATH)
11810/* Lookup to encode one byte directly into 2 characters:
11811 *
11812 * def genhextab(bswap):
11813 * for i in xrange(256):
11814 * t = chr(i).encode('hex')
11815 * if bswap:
11816 * t = t[1] + t[0]
11817 * print('0x' + t.encode('hex') + 'U')
11818 * print('big endian'); genhextab(False)
11819 * print('little endian'); genhextab(True)
11820*/
11821DUK_INTERNAL const duk_uint16_t duk_hex_enctab[256] = {
11822#if defined(DUK_USE_INTEGER_BE)
11823 0x3030U, 0x3031U, 0x3032U, 0x3033U, 0x3034U, 0x3035U, 0x3036U, 0x3037U,
11824 0x3038U, 0x3039U, 0x3061U, 0x3062U, 0x3063U, 0x3064U, 0x3065U, 0x3066U,
11825 0x3130U, 0x3131U, 0x3132U, 0x3133U, 0x3134U, 0x3135U, 0x3136U, 0x3137U,
11826 0x3138U, 0x3139U, 0x3161U, 0x3162U, 0x3163U, 0x3164U, 0x3165U, 0x3166U,
11827 0x3230U, 0x3231U, 0x3232U, 0x3233U, 0x3234U, 0x3235U, 0x3236U, 0x3237U,
11828 0x3238U, 0x3239U, 0x3261U, 0x3262U, 0x3263U, 0x3264U, 0x3265U, 0x3266U,
11829 0x3330U, 0x3331U, 0x3332U, 0x3333U, 0x3334U, 0x3335U, 0x3336U, 0x3337U,
11830 0x3338U, 0x3339U, 0x3361U, 0x3362U, 0x3363U, 0x3364U, 0x3365U, 0x3366U,
11831 0x3430U, 0x3431U, 0x3432U, 0x3433U, 0x3434U, 0x3435U, 0x3436U, 0x3437U,
11832 0x3438U, 0x3439U, 0x3461U, 0x3462U, 0x3463U, 0x3464U, 0x3465U, 0x3466U,
11833 0x3530U, 0x3531U, 0x3532U, 0x3533U, 0x3534U, 0x3535U, 0x3536U, 0x3537U,
11834 0x3538U, 0x3539U, 0x3561U, 0x3562U, 0x3563U, 0x3564U, 0x3565U, 0x3566U,
11835 0x3630U, 0x3631U, 0x3632U, 0x3633U, 0x3634U, 0x3635U, 0x3636U, 0x3637U,
11836 0x3638U, 0x3639U, 0x3661U, 0x3662U, 0x3663U, 0x3664U, 0x3665U, 0x3666U,
11837 0x3730U, 0x3731U, 0x3732U, 0x3733U, 0x3734U, 0x3735U, 0x3736U, 0x3737U,
11838 0x3738U, 0x3739U, 0x3761U, 0x3762U, 0x3763U, 0x3764U, 0x3765U, 0x3766U,
11839 0x3830U, 0x3831U, 0x3832U, 0x3833U, 0x3834U, 0x3835U, 0x3836U, 0x3837U,
11840 0x3838U, 0x3839U, 0x3861U, 0x3862U, 0x3863U, 0x3864U, 0x3865U, 0x3866U,
11841 0x3930U, 0x3931U, 0x3932U, 0x3933U, 0x3934U, 0x3935U, 0x3936U, 0x3937U,
11842 0x3938U, 0x3939U, 0x3961U, 0x3962U, 0x3963U, 0x3964U, 0x3965U, 0x3966U,
11843 0x6130U, 0x6131U, 0x6132U, 0x6133U, 0x6134U, 0x6135U, 0x6136U, 0x6137U,
11844 0x6138U, 0x6139U, 0x6161U, 0x6162U, 0x6163U, 0x6164U, 0x6165U, 0x6166U,
11845 0x6230U, 0x6231U, 0x6232U, 0x6233U, 0x6234U, 0x6235U, 0x6236U, 0x6237U,
11846 0x6238U, 0x6239U, 0x6261U, 0x6262U, 0x6263U, 0x6264U, 0x6265U, 0x6266U,
11847 0x6330U, 0x6331U, 0x6332U, 0x6333U, 0x6334U, 0x6335U, 0x6336U, 0x6337U,
11848 0x6338U, 0x6339U, 0x6361U, 0x6362U, 0x6363U, 0x6364U, 0x6365U, 0x6366U,
11849 0x6430U, 0x6431U, 0x6432U, 0x6433U, 0x6434U, 0x6435U, 0x6436U, 0x6437U,
11850 0x6438U, 0x6439U, 0x6461U, 0x6462U, 0x6463U, 0x6464U, 0x6465U, 0x6466U,
11851 0x6530U, 0x6531U, 0x6532U, 0x6533U, 0x6534U, 0x6535U, 0x6536U, 0x6537U,
11852 0x6538U, 0x6539U, 0x6561U, 0x6562U, 0x6563U, 0x6564U, 0x6565U, 0x6566U,
11853 0x6630U, 0x6631U, 0x6632U, 0x6633U, 0x6634U, 0x6635U, 0x6636U, 0x6637U,
11854 0x6638U, 0x6639U, 0x6661U, 0x6662U, 0x6663U, 0x6664U, 0x6665U, 0x6666U
11855#else /* DUK_USE_INTEGER_BE */
11856 0x3030U, 0x3130U, 0x3230U, 0x3330U, 0x3430U, 0x3530U, 0x3630U, 0x3730U,
11857 0x3830U, 0x3930U, 0x6130U, 0x6230U, 0x6330U, 0x6430U, 0x6530U, 0x6630U,
11858 0x3031U, 0x3131U, 0x3231U, 0x3331U, 0x3431U, 0x3531U, 0x3631U, 0x3731U,
11859 0x3831U, 0x3931U, 0x6131U, 0x6231U, 0x6331U, 0x6431U, 0x6531U, 0x6631U,
11860 0x3032U, 0x3132U, 0x3232U, 0x3332U, 0x3432U, 0x3532U, 0x3632U, 0x3732U,
11861 0x3832U, 0x3932U, 0x6132U, 0x6232U, 0x6332U, 0x6432U, 0x6532U, 0x6632U,
11862 0x3033U, 0x3133U, 0x3233U, 0x3333U, 0x3433U, 0x3533U, 0x3633U, 0x3733U,
11863 0x3833U, 0x3933U, 0x6133U, 0x6233U, 0x6333U, 0x6433U, 0x6533U, 0x6633U,
11864 0x3034U, 0x3134U, 0x3234U, 0x3334U, 0x3434U, 0x3534U, 0x3634U, 0x3734U,
11865 0x3834U, 0x3934U, 0x6134U, 0x6234U, 0x6334U, 0x6434U, 0x6534U, 0x6634U,
11866 0x3035U, 0x3135U, 0x3235U, 0x3335U, 0x3435U, 0x3535U, 0x3635U, 0x3735U,
11867 0x3835U, 0x3935U, 0x6135U, 0x6235U, 0x6335U, 0x6435U, 0x6535U, 0x6635U,
11868 0x3036U, 0x3136U, 0x3236U, 0x3336U, 0x3436U, 0x3536U, 0x3636U, 0x3736U,
11869 0x3836U, 0x3936U, 0x6136U, 0x6236U, 0x6336U, 0x6436U, 0x6536U, 0x6636U,
11870 0x3037U, 0x3137U, 0x3237U, 0x3337U, 0x3437U, 0x3537U, 0x3637U, 0x3737U,
11871 0x3837U, 0x3937U, 0x6137U, 0x6237U, 0x6337U, 0x6437U, 0x6537U, 0x6637U,
11872 0x3038U, 0x3138U, 0x3238U, 0x3338U, 0x3438U, 0x3538U, 0x3638U, 0x3738U,
11873 0x3838U, 0x3938U, 0x6138U, 0x6238U, 0x6338U, 0x6438U, 0x6538U, 0x6638U,
11874 0x3039U, 0x3139U, 0x3239U, 0x3339U, 0x3439U, 0x3539U, 0x3639U, 0x3739U,
11875 0x3839U, 0x3939U, 0x6139U, 0x6239U, 0x6339U, 0x6439U, 0x6539U, 0x6639U,
11876 0x3061U, 0x3161U, 0x3261U, 0x3361U, 0x3461U, 0x3561U, 0x3661U, 0x3761U,
11877 0x3861U, 0x3961U, 0x6161U, 0x6261U, 0x6361U, 0x6461U, 0x6561U, 0x6661U,
11878 0x3062U, 0x3162U, 0x3262U, 0x3362U, 0x3462U, 0x3562U, 0x3662U, 0x3762U,
11879 0x3862U, 0x3962U, 0x6162U, 0x6262U, 0x6362U, 0x6462U, 0x6562U, 0x6662U,
11880 0x3063U, 0x3163U, 0x3263U, 0x3363U, 0x3463U, 0x3563U, 0x3663U, 0x3763U,
11881 0x3863U, 0x3963U, 0x6163U, 0x6263U, 0x6363U, 0x6463U, 0x6563U, 0x6663U,
11882 0x3064U, 0x3164U, 0x3264U, 0x3364U, 0x3464U, 0x3564U, 0x3664U, 0x3764U,
11883 0x3864U, 0x3964U, 0x6164U, 0x6264U, 0x6364U, 0x6464U, 0x6564U, 0x6664U,
11884 0x3065U, 0x3165U, 0x3265U, 0x3365U, 0x3465U, 0x3565U, 0x3665U, 0x3765U,
11885 0x3865U, 0x3965U, 0x6165U, 0x6265U, 0x6365U, 0x6465U, 0x6565U, 0x6665U,
11886 0x3066U, 0x3166U, 0x3266U, 0x3366U, 0x3466U, 0x3566U, 0x3666U, 0x3766U,
11887 0x3866U, 0x3966U, 0x6166U, 0x6266U, 0x6366U, 0x6466U, 0x6566U, 0x6666U
11888#endif /* DUK_USE_INTEGER_BE */
11889};
11890#endif /* DUK_USE_HEX_FASTPATH */
11891
11892/*
11893 * Table for base-64 encoding
11894 */
11895
11896#if defined(DUK_USE_BASE64_FASTPATH)
11897DUK_INTERNAL const duk_uint8_t duk_base64_enctab[64] = {
11898 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, /* A...P */
11899 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, /* Q...f */
11900 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, /* g...v */
11901 0x77, 0x78, 0x79, 0x7a, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2b, 0x2f /* w.../ */
11902};
11903#endif /* DUK_USE_BASE64_FASTPATH */
11904
11905/*
11906 * Table for base-64 decoding
11907 */
11908
11909#if defined(DUK_USE_BASE64_FASTPATH)
11910DUK_INTERNAL const duk_int8_t duk_base64_dectab[256] = {
11911 /* -1 = error, -2 = allowed whitespace, -3 = padding ('='), 0...63 decoded bytes */
11912 -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -1, -1, -2, -1, -1, /* 0x00...0x0f */
11913 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10...0x1f */
11914 -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20...0x2f */
11915 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -3, -1, -1, /* 0x30...0x3f */
11916 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40...0x4f */
11917 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50...0x5f */
11918 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60...0x6f */
11919 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, /* 0x70...0x7f */
11920 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x80...0x8f */
11921 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x90...0x9f */
11922 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xa0...0xaf */
11923 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xb0...0xbf */
11924 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xc0...0xcf */
11925 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xd0...0xdf */
11926 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0xe0...0xef */
11927 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 0xf0...0xff */
11928};
11929#endif /* DUK_USE_BASE64_FASTPATH */
11930
11931/*
11932 * Arbitrary byteswap for potentially unaligned values
11933 *
11934 * Used to byteswap pointers e.g. in debugger code.
11935 */
11936
11937#if defined(DUK_USE_DEBUGGER_SUPPORT) /* For now only needed by the debugger. */
11938DUK_INTERNAL void duk_byteswap_bytes(duk_uint8_t *p, duk_small_uint_t len) {
11939 duk_uint8_t tmp;
11940 duk_uint8_t *q = p + len - 1;
11941
11942 while (p - q < 0) {
11943 tmp = *p;
11944 *p = *q;
11945 *q = tmp;
11946 p++;
11947 q--;
11948 }
11949}
11950#endif
11951
11952/*
11953 * Miscellaneous coercion / clamping helpers.
11954 */
11955
11956/* Check whether a duk_double_t is a whole number in the 32-bit range (reject
11957 * negative zero), and if so, return a duk_int32_t.
11958 * For compiler use: don't allow negative zero as it will cause trouble with
11959 * LDINT+LDINTX, positive zero is OK.
11960 */
11961DUK_INTERNAL duk_bool_t duk_is_whole_get_int32_nonegzero(duk_double_t x, duk_int32_t *ival) {
11962 duk_int32_t t;
11963
11964 t = (duk_int32_t) x;
11965 if (!((duk_double_t) t == x)) {
11966 return 0;
11967 }
11968 if (t == 0) {
11970 du.d = x;
11971 if (DUK_DBLUNION_HAS_SIGNBIT(&du)) {
11972 return 0;
11973 }
11974 }
11975 *ival = t;
11976 return 1;
11977}
11978
11979/* Check whether a duk_double_t is a whole number in the 32-bit range, and if
11980 * so, return a duk_int32_t.
11981 */
11982DUK_INTERNAL duk_bool_t duk_is_whole_get_int32(duk_double_t x, duk_int32_t *ival) {
11983 duk_int32_t t;
11984
11985 t = (duk_int32_t) x;
11986 if (!((duk_double_t) t == x)) {
11987 return 0;
11988 }
11989 *ival = t;
11990 return 1;
11991}
11992
11993/*
11994 * IEEE double checks
11995 */
11996
11997DUK_INTERNAL duk_bool_t duk_double_is_anyinf(duk_double_t x) {
11999 du.d = x;
12000 return DUK_DBLUNION_IS_ANYINF(&du);
12001}
12002
12003DUK_INTERNAL duk_bool_t duk_double_is_posinf(duk_double_t x) {
12005 du.d = x;
12006 return DUK_DBLUNION_IS_POSINF(&du);
12007}
12008
12009DUK_INTERNAL duk_bool_t duk_double_is_neginf(duk_double_t x) {
12011 du.d = x;
12012 return DUK_DBLUNION_IS_NEGINF(&du);
12013}
12014
12015DUK_INTERNAL duk_bool_t duk_double_is_nan(duk_double_t x) {
12017 du.d = x;
12018 /* Assumes we're dealing with a Duktape internal NaN which is
12019 * NaN normalized if duk_tval requires it.
12020 */
12021 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
12022 return DUK_DBLUNION_IS_NAN(&du);
12023}
12024
12025DUK_INTERNAL duk_bool_t duk_double_is_nan_or_zero(duk_double_t x) {
12027 du.d = x;
12028 /* Assumes we're dealing with a Duktape internal NaN which is
12029 * NaN normalized if duk_tval requires it.
12030 */
12031 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
12032 return DUK_DBLUNION_IS_NAN(&du) || DUK_DBLUNION_IS_ANYZERO(&du);
12033}
12034
12035DUK_INTERNAL duk_bool_t duk_double_is_nan_or_inf(duk_double_t x) {
12037 du.d = x;
12038 /* If exponent is 0x7FF the argument is either a NaN or an
12039 * infinity. We don't need to check any other fields.
12040 */
12041#if defined(DUK_USE_64BIT_OPS)
12042#if defined(DUK_USE_DOUBLE_ME)
12043 return (du.ull[DUK_DBL_IDX_ULL0] & 0x000000007ff00000ULL) == 0x000000007ff00000ULL;
12044#else
12045 return (du.ull[DUK_DBL_IDX_ULL0] & 0x7ff0000000000000ULL) == 0x7ff0000000000000ULL;
12046#endif
12047#else
12048 return (du.ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL) == 0x7ff00000UL;
12049#endif
12050}
12051
12052DUK_INTERNAL duk_bool_t duk_double_is_nan_zero_inf(duk_double_t x) {
12054#if defined(DUK_USE_64BIT_OPS)
12055 duk_uint64_t t;
12056#else
12057 duk_uint32_t t;
12058#endif
12059 du.d = x;
12060#if defined(DUK_USE_64BIT_OPS)
12061#if defined(DUK_USE_DOUBLE_ME)
12062 t = du.ull[DUK_DBL_IDX_ULL0] & 0x000000007ff00000ULL;
12063 if (t == 0x0000000000000000ULL) {
12064 t = du.ull[DUK_DBL_IDX_ULL0] & 0x0000000080000000ULL;
12065 return t == 0;
12066 }
12067 if (t == 0x000000007ff00000UL) {
12068 return 1;
12069 }
12070#else
12071 t = du.ull[DUK_DBL_IDX_ULL0] & 0x7ff0000000000000ULL;
12072 if (t == 0x0000000000000000ULL) {
12073 t = du.ull[DUK_DBL_IDX_ULL0] & 0x8000000000000000ULL;
12074 return t == 0;
12075 }
12076 if (t == 0x7ff0000000000000ULL) {
12077 return 1;
12078 }
12079#endif
12080#else
12081 t = du.ui[DUK_DBL_IDX_UI0] & 0x7ff00000UL;
12082 if (t == 0x00000000UL) {
12083 return DUK_DBLUNION_IS_ANYZERO(&du);
12084 }
12085 if (t == 0x7ff00000UL) {
12086 return 1;
12087 }
12088#endif
12089 return 0;
12090}
12091
12092DUK_INTERNAL duk_small_uint_t duk_double_signbit(duk_double_t x) {
12094 du.d = x;
12095 return (duk_small_uint_t) DUK_DBLUNION_GET_SIGNBIT(&du);
12096}
12097
12098DUK_INTERNAL duk_double_t duk_double_trunc_towards_zero(duk_double_t x) {
12099 /* XXX: optimize */
12100 duk_small_int_t s = duk_double_signbit(x);
12101 x = DUK_FLOOR(DUK_FABS(x)); /* truncate towards zero */
12102 if (s) {
12103 x = -x;
12104 }
12105 return x;
12106}
12107
12108DUK_INTERNAL duk_bool_t duk_double_same_sign(duk_double_t x, duk_double_t y) {
12109 duk_double_union du1;
12110 duk_double_union du2;
12111 du1.d = x;
12112 du2.d = y;
12113
12114 return (((du1.ui[DUK_DBL_IDX_UI0] ^ du2.ui[DUK_DBL_IDX_UI0]) & 0x80000000UL) == 0);
12115}
12116
12117DUK_INTERNAL duk_double_t duk_double_fmin(duk_double_t x, duk_double_t y) {
12118 /* Doesn't replicate fmin() behavior exactly: for fmin() if one
12119 * argument is a NaN, the other argument should be returned.
12120 * Duktape doesn't rely on this behavior so the replacement can
12121 * be simplified.
12122 */
12123 return (x < y ? x : y);
12124}
12125
12126DUK_INTERNAL duk_double_t duk_double_fmax(duk_double_t x, duk_double_t y) {
12127 /* Doesn't replicate fmax() behavior exactly: for fmax() if one
12128 * argument is a NaN, the other argument should be returned.
12129 * Duktape doesn't rely on this behavior so the replacement can
12130 * be simplified.
12131 */
12132 return (x > y ? x : y);
12133}
12134/*
12135 * Round a number upwards to a prime (not usually the nearest one).
12136 *
12137 * Uses a table of successive 32-bit primes whose ratio is roughly
12138 * constant. This keeps the relative upwards 'rounding error' bounded
12139 * and the data size small. A simple 'predict-correct' compression is
12140 * used to compress primes to one byte per prime. See genhashsizes.py
12141 * for details.
12142 *
12143 * The minimum prime returned here must be coordinated with the possible
12144 * probe sequence steps in duk_hobject and duk_heap stringtable.
12145 */
12146
12147/* #include duk_internal.h -> already included */
12148
12149/* Awkward inclusion condition: drop out of compilation if not needed by any
12150 * call site: object hash part or probing stringtable.
12151 */
12152#if defined(DUK_USE_HOBJECT_HASH_PART) || defined(DUK_USE_STRTAB_PROBE)
12153
12154/* hash size ratio goal, must match genhashsizes.py */
12155#define DUK__HASH_SIZE_RATIO 1177 /* floor(1.15 * (1 << 10)) */
12156
12157/* prediction corrections for prime list (see genhashsizes.py) */
12158DUK_LOCAL const duk_int8_t duk__hash_size_corrections[] = {
12159 17, /* minimum prime */
12160 4, 3, 4, 1, 4, 1, 1, 2, 2, 2, 2, 1, 6, 6, 9, 5, 1, 2, 2, 5, 1, 3, 3, 3,
12161 5, 4, 4, 2, 4, 8, 3, 4, 23, 2, 4, 7, 8, 11, 2, 12, 15, 10, 1, 1, 5, 1, 5,
12162 8, 9, 17, 14, 10, 7, 5, 2, 46, 21, 1, 9, 9, 4, 4, 10, 23, 36, 6, 20, 29,
12163 18, 6, 19, 21, 16, 11, 5, 5, 48, 9, 1, 39, 14, 8, 4, 29, 9, 1, 15, 48, 12,
12164 22, 6, 15, 27, 4, 2, 17, 28, 8, 9, 4, 5, 8, 3, 3, 8, 37, 11, 15, 8, 30,
12165 43, 6, 33, 41, 5, 20, 32, 41, 38, 24, 77, 14, 19, 11, 4, 35, 18, 19, 41,
12166 10, 23, 16, 9, 2,
12167 -1
12168};
12169
12170/* probe steps (see genhashsizes.py), currently assumed to be 32 entries long
12171 * (DUK_UTIL_GET_HASH_PROBE_STEP macro).
12172 */
12173DUK_INTERNAL duk_uint8_t duk_util_probe_steps[32] = {
12174 2, 3, 5, 7, 11, 13, 19, 31, 41, 47, 59, 67, 73, 79, 89, 101, 103, 107,
12175 109, 127, 137, 139, 149, 157, 163, 167, 173, 181, 191, 193, 197, 199
12176};
12177
12178DUK_INTERNAL duk_uint32_t duk_util_get_hash_prime(duk_uint32_t size) {
12179 const duk_int8_t *p = duk__hash_size_corrections;
12180 duk_uint32_t curr;
12181
12182 curr = (duk_uint32_t) *p++;
12183 for (;;) {
12184 duk_small_int_t t = (duk_small_int_t) *p++;
12185 if (t < 0) {
12186 /* may happen if size is very close to 2^32-1 */
12187 break;
12188 }
12189
12190 /* prediction: portable variant using doubles if 64-bit values not available */
12191#if defined(DUK_USE_64BIT_OPS)
12192 curr = (duk_uint32_t) ((((duk_uint64_t) curr) * ((duk_uint64_t) DUK__HASH_SIZE_RATIO)) >> 10);
12193#else
12194 /* 32-bit x 11-bit = 43-bit, fits accurately into a double */
12195 curr = (duk_uint32_t) DUK_FLOOR(((double) curr) * ((double) DUK__HASH_SIZE_RATIO) / 1024.0);
12196#endif
12197
12198 /* correction */
12199 curr += t;
12200
12201 DUK_DDD(DUK_DDDPRINT("size=%ld, curr=%ld", (long) size, (long) curr));
12202
12203 if (curr >= size) {
12204 return curr;
12205 }
12206 }
12207 return 0;
12208}
12209
12210#endif /* DUK_USE_HOBJECT_HASH_PART || DUK_USE_STRTAB_PROBE */
12211
12212/* automatic undefs */
12213#undef DUK__HASH_SIZE_RATIO
12214/*
12215 * Hobject Ecmascript [[Class]].
12216 */
12217
12218/* #include duk_internal.h -> already included */
12219
12220#if (DUK_STRIDX_UC_ARGUMENTS > 255)
12221#error constant too large
12222#endif
12223#if (DUK_STRIDX_ARRAY > 255)
12224#error constant too large
12225#endif
12226#if (DUK_STRIDX_UC_BOOLEAN > 255)
12227#error constant too large
12228#endif
12229#if (DUK_STRIDX_DATE > 255)
12230#error constant too large
12231#endif
12232#if (DUK_STRIDX_UC_ERROR > 255)
12233#error constant too large
12234#endif
12235#if (DUK_STRIDX_UC_FUNCTION > 255)
12236#error constant too large
12237#endif
12238#if (DUK_STRIDX_JSON > 255)
12239#error constant too large
12240#endif
12241#if (DUK_STRIDX_MATH > 255)
12242#error constant too large
12243#endif
12244#if (DUK_STRIDX_UC_NUMBER > 255)
12245#error constant too large
12246#endif
12247#if (DUK_STRIDX_UC_OBJECT > 255)
12248#error constant too large
12249#endif
12250#if (DUK_STRIDX_REG_EXP > 255)
12251#error constant too large
12252#endif
12253#if (DUK_STRIDX_UC_STRING > 255)
12254#error constant too large
12255#endif
12256#if (DUK_STRIDX_GLOBAL > 255)
12257#error constant too large
12258#endif
12259#if (DUK_STRIDX_OBJ_ENV > 255)
12260#error constant too large
12261#endif
12262#if (DUK_STRIDX_DEC_ENV > 255)
12263#error constant too large
12264#endif
12265#if (DUK_STRIDX_UC_POINTER > 255)
12266#error constant too large
12267#endif
12268#if (DUK_STRIDX_UC_THREAD > 255)
12269#error constant too large
12270#endif
12271#if (DUK_STRIDX_ARRAY_BUFFER > 255)
12272#error constant too large
12273#endif
12274#if (DUK_STRIDX_DATA_VIEW > 255)
12275#error constant too large
12276#endif
12277#if (DUK_STRIDX_INT8_ARRAY > 255)
12278#error constant too large
12279#endif
12280#if (DUK_STRIDX_UINT8_ARRAY > 255)
12281#error constant too large
12282#endif
12283#if (DUK_STRIDX_UINT8_CLAMPED_ARRAY > 255)
12284#error constant too large
12285#endif
12286#if (DUK_STRIDX_INT16_ARRAY > 255)
12287#error constant too large
12288#endif
12289#if (DUK_STRIDX_UINT16_ARRAY > 255)
12290#error constant too large
12291#endif
12292#if (DUK_STRIDX_INT32_ARRAY > 255)
12293#error constant too large
12294#endif
12295#if (DUK_STRIDX_UINT32_ARRAY > 255)
12296#error constant too large
12297#endif
12298#if (DUK_STRIDX_FLOAT32_ARRAY > 255)
12299#error constant too large
12300#endif
12301#if (DUK_STRIDX_FLOAT64_ARRAY > 255)
12302#error constant too large
12303#endif
12304#if (DUK_STRIDX_EMPTY_STRING > 255)
12305#error constant too large
12306#endif
12307
12308/* Note: assumes that these string indexes are 8-bit, genstrings.py must ensure that */
12309DUK_INTERNAL duk_uint8_t duk_class_number_to_stridx[32] = {
12310 DUK_STRIDX_EMPTY_STRING, /* NONE, intentionally empty */
12311 DUK_STRIDX_UC_OBJECT,
12312 DUK_STRIDX_ARRAY,
12313 DUK_STRIDX_UC_FUNCTION,
12314 DUK_STRIDX_UC_ARGUMENTS,
12315 DUK_STRIDX_UC_BOOLEAN,
12316 DUK_STRIDX_DATE,
12317 DUK_STRIDX_UC_ERROR,
12318 DUK_STRIDX_JSON,
12319 DUK_STRIDX_MATH,
12320 DUK_STRIDX_UC_NUMBER,
12321 DUK_STRIDX_REG_EXP,
12322 DUK_STRIDX_UC_STRING,
12323 DUK_STRIDX_GLOBAL,
12324 DUK_STRIDX_UC_SYMBOL,
12325 DUK_STRIDX_OBJ_ENV,
12326 DUK_STRIDX_DEC_ENV,
12327 DUK_STRIDX_UC_POINTER,
12328 DUK_STRIDX_UC_THREAD,
12329 DUK_STRIDX_ARRAY_BUFFER,
12330 DUK_STRIDX_DATA_VIEW,
12331 DUK_STRIDX_INT8_ARRAY,
12332 DUK_STRIDX_UINT8_ARRAY,
12333 DUK_STRIDX_UINT8_CLAMPED_ARRAY,
12334 DUK_STRIDX_INT16_ARRAY,
12335 DUK_STRIDX_UINT16_ARRAY,
12336 DUK_STRIDX_INT32_ARRAY,
12337 DUK_STRIDX_UINT32_ARRAY,
12338 DUK_STRIDX_FLOAT32_ARRAY,
12339 DUK_STRIDX_FLOAT64_ARRAY,
12340 DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */
12341 DUK_STRIDX_EMPTY_STRING, /* UNUSED, intentionally empty */
12342};
12343/*
12344 * Default allocation functions.
12345 *
12346 * Assumes behavior such as malloc allowing zero size, yielding
12347 * a NULL or a unique pointer which is a no-op for free.
12348 */
12349
12350/* #include duk_internal.h -> already included */
12351
12352#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS)
12353DUK_INTERNAL void *duk_default_alloc_function(void *udata, duk_size_t size) {
12354 void *res;
12355 DUK_UNREF(udata);
12356 res = DUK_ANSI_MALLOC(size);
12357 DUK_DDD(DUK_DDDPRINT("default alloc function: %lu -> %p",
12358 (unsigned long) size, (void *) res));
12359 return res;
12360}
12361
12362DUK_INTERNAL void *duk_default_realloc_function(void *udata, void *ptr, duk_size_t newsize) {
12363 void *res;
12364 DUK_UNREF(udata);
12365 res = DUK_ANSI_REALLOC(ptr, newsize);
12366 DUK_DDD(DUK_DDDPRINT("default realloc function: %p %lu -> %p",
12367 (void *) ptr, (unsigned long) newsize, (void *) res));
12368 return res;
12369}
12370
12371DUK_INTERNAL void duk_default_free_function(void *udata, void *ptr) {
12372 DUK_DDD(DUK_DDDPRINT("default free function: %p", (void *) ptr));
12373 DUK_UNREF(udata);
12374 DUK_ANSI_FREE(ptr);
12375}
12376#endif /* DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS */
12377/*
12378 * Buffer
12379 */
12380
12381/* #include duk_internal.h -> already included */
12382
12383DUK_EXTERNAL void *duk_resize_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t new_size) {
12384 duk_hthread *thr = (duk_hthread *) ctx;
12386
12387 DUK_ASSERT_CTX_VALID(ctx);
12388
12389 h = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, idx);
12390 DUK_ASSERT(h != NULL);
12391
12392 if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) {
12393 DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE);
12394 }
12395
12396 /* maximum size check is handled by callee */
12397 duk_hbuffer_resize(thr, h, new_size);
12398
12399 return DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h);
12400}
12401
12402DUK_EXTERNAL void *duk_steal_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) {
12403 duk_hthread *thr = (duk_hthread *) ctx;
12405 void *ptr;
12406 duk_size_t sz;
12407
12408 DUK_ASSERT(ctx != NULL);
12409
12410 h = (duk_hbuffer_dynamic *) duk_require_hbuffer(ctx, idx);
12411 DUK_ASSERT(h != NULL);
12412
12413 if (!(DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h))) {
12414 DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE);
12415 }
12416
12417 /* Forget the previous allocation, setting size to 0 and alloc to
12418 * NULL. Caller is responsible for freeing the previous allocation.
12419 * Getting the allocation and clearing it is done in the same API
12420 * call to avoid any chance of a realloc.
12421 */
12422 ptr = DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h);
12423 sz = DUK_HBUFFER_DYNAMIC_GET_SIZE(h);
12424 if (out_size) {
12425 *out_size = sz;
12426 }
12427 DUK_HBUFFER_DYNAMIC_SET_DATA_PTR_NULL(thr->heap, h);
12428 DUK_HBUFFER_DYNAMIC_SET_SIZE(h, 0);
12429
12430 return ptr;
12431}
12432
12433DUK_EXTERNAL void duk_config_buffer(duk_context *ctx, duk_idx_t idx, void *ptr, duk_size_t len) {
12434 duk_hthread *thr = (duk_hthread *) ctx;
12436
12437 DUK_ASSERT(ctx != NULL);
12438
12439 h = (duk_hbuffer_external *) duk_require_hbuffer(ctx, idx);
12440 DUK_ASSERT(h != NULL);
12441
12442 if (!DUK_HBUFFER_HAS_EXTERNAL(h)) {
12443 DUK_ERROR_TYPE(thr, DUK_STR_WRONG_BUFFER_TYPE);
12444 }
12445 DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h));
12446
12447 DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(thr->heap, h, ptr);
12448 DUK_HBUFFER_EXTERNAL_SET_SIZE(h, len);
12449}
12450/*
12451 * Bytecode dump/load
12452 *
12453 * The bytecode load primitive is more important performance-wise than the
12454 * dump primitive.
12455 *
12456 * Unlike most Duktape API calls, bytecode dump/load is not guaranteed to be
12457 * memory safe for invalid arguments - caller beware! There's little point
12458 * in trying to achieve memory safety unless bytecode instructions are also
12459 * validated which is not easy to do with indirect register references etc.
12460 */
12461
12462/* #include duk_internal.h -> already included */
12463
12464#if defined(DUK_USE_BYTECODE_DUMP_SUPPORT)
12465
12466#define DUK__SER_MARKER 0xff
12467#define DUK__SER_VERSION 0x00
12468#define DUK__SER_STRING 0x00
12469#define DUK__SER_NUMBER 0x01
12470#define DUK__BYTECODE_INITIAL_ALLOC 256
12471
12472/*
12473 * Dump/load helpers, xxx_raw() helpers do no buffer checks
12474 */
12475
12476DUK_LOCAL duk_uint8_t *duk__load_string_raw(duk_context *ctx, duk_uint8_t *p) {
12477 duk_uint32_t len;
12478
12479 len = DUK_RAW_READ_U32_BE(p);
12480 duk_push_lstring(ctx, (const char *) p, len);
12481 p += len;
12482 return p;
12483}
12484
12485DUK_LOCAL duk_uint8_t *duk__load_buffer_raw(duk_context *ctx, duk_uint8_t *p) {
12486 duk_uint32_t len;
12487 duk_uint8_t *buf;
12488
12489 len = DUK_RAW_READ_U32_BE(p);
12490 buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, (duk_size_t) len);
12491 DUK_ASSERT(buf != NULL);
12492 DUK_MEMCPY((void *) buf, (const void *) p, (size_t) len);
12493 p += len;
12494 return p;
12495}
12496
12497DUK_LOCAL duk_uint8_t *duk__dump_hstring_raw(duk_uint8_t *p, duk_hstring *h) {
12498 duk_size_t len;
12499 duk_uint32_t tmp32;
12500
12501 DUK_ASSERT(h != NULL);
12502
12503 len = DUK_HSTRING_GET_BYTELEN(h);
12504 DUK_ASSERT(len <= 0xffffffffUL); /* string limits */
12505 tmp32 = (duk_uint32_t) len;
12506 DUK_RAW_WRITE_U32_BE(p, tmp32);
12507 DUK_MEMCPY((void *) p,
12508 (const void *) DUK_HSTRING_GET_DATA(h),
12509 len);
12510 p += len;
12511 return p;
12512}
12513
12514DUK_LOCAL duk_uint8_t *duk__dump_hbuffer_raw(duk_hthread *thr, duk_uint8_t *p, duk_hbuffer *h) {
12515 duk_size_t len;
12516 duk_uint32_t tmp32;
12517
12518 DUK_ASSERT(thr != NULL);
12519 DUK_ASSERT(h != NULL);
12520 DUK_UNREF(thr);
12521
12522 len = DUK_HBUFFER_GET_SIZE(h);
12523 DUK_ASSERT(len <= 0xffffffffUL); /* buffer limits */
12524 tmp32 = (duk_uint32_t) len;
12525 DUK_RAW_WRITE_U32_BE(p, tmp32);
12526 DUK_MEMCPY((void *) p,
12527 (const void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h),
12528 len);
12529 p += len;
12530 return p;
12531}
12532
12533DUK_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) {
12534 duk_hstring *h_str;
12535 duk_tval *tv;
12536
12537 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_GET_STRING(thr, stridx));
12538 if (tv != NULL && DUK_TVAL_IS_STRING(tv)) {
12539 h_str = DUK_TVAL_GET_STRING(tv);
12540 DUK_ASSERT(h_str != NULL);
12541 } else {
12542 h_str = DUK_HTHREAD_STRING_EMPTY_STRING(thr);
12543 DUK_ASSERT(h_str != NULL);
12544 }
12545 DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
12546 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(h_str), p);
12547 p = duk__dump_hstring_raw(p, h_str);
12548 return p;
12549}
12550
12551DUK_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) {
12552 duk_tval *tv;
12553
12554 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_GET_STRING(thr, stridx));
12555 if (tv != NULL && DUK_TVAL_IS_BUFFER(tv)) {
12556 duk_hbuffer *h_buf;
12557 h_buf = DUK_TVAL_GET_BUFFER(tv);
12558 DUK_ASSERT(h_buf != NULL);
12559 DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
12560 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HBUFFER_GET_SIZE(h_buf), p);
12561 p = duk__dump_hbuffer_raw(thr, p, h_buf);
12562 } else {
12563 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
12564 DUK_RAW_WRITE_U32_BE(p, 0);
12565 }
12566 return p;
12567}
12568
12569DUK_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) {
12570 duk_tval *tv;
12571 duk_uint32_t val;
12572
12573 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_GET_STRING(thr, stridx));
12574 if (tv != NULL && DUK_TVAL_IS_NUMBER(tv)) {
12575 val = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv);
12576 } else {
12577 val = def_value;
12578 }
12579 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
12580 DUK_RAW_WRITE_U32_BE(p, val);
12581 return p;
12582}
12583
12584DUK_LOCAL duk_uint8_t *duk__dump_varmap(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func) {
12585 duk_tval *tv;
12586
12587 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_STRING_INT_VARMAP(thr));
12588 if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) {
12589 duk_hobject *h;
12590 duk_uint_fast32_t i;
12591
12592 h = DUK_TVAL_GET_OBJECT(tv);
12593 DUK_ASSERT(h != NULL);
12594
12595 /* We know _Varmap only has own properties so walk property
12596 * table directly. We also know _Varmap is dense and all
12597 * values are numbers; assert for these. GC and finalizers
12598 * shouldn't affect _Varmap so side effects should be fine.
12599 */
12600 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
12602 duk_tval *tv_val;
12603 duk_uint32_t val;
12604
12605 key = DUK_HOBJECT_E_GET_KEY(thr->heap, h, i);
12606 DUK_ASSERT(key != NULL); /* _Varmap is dense */
12607 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h, i));
12608 tv_val = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, h, i);
12609 DUK_ASSERT(tv_val != NULL);
12610 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_val)); /* known to be number; in fact an integer */
12611#if defined(DUK_USE_FASTINT)
12612 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv_val));
12613 DUK_ASSERT(DUK_TVAL_GET_FASTINT(tv_val) == (duk_int64_t) DUK_TVAL_GET_FASTINT_U32(tv_val)); /* known to be 32-bit */
12614 val = DUK_TVAL_GET_FASTINT_U32(tv_val);
12615#else
12616 val = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv_val);
12617#endif
12618
12619 DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
12620 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(key) + 4, p);
12621 p = duk__dump_hstring_raw(p, key);
12622 DUK_RAW_WRITE_U32_BE(p, val);
12623 }
12624 }
12625 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
12626 DUK_RAW_WRITE_U32_BE(p, 0); /* end of _Varmap */
12627 return p;
12628}
12629
12630DUK_LOCAL duk_uint8_t *duk__dump_formals(duk_hthread *thr, duk_uint8_t *p, duk_bufwriter_ctx *bw_ctx, duk_hobject *func) {
12631 duk_tval *tv;
12632
12633 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) func, DUK_HTHREAD_STRING_INT_FORMALS(thr));
12634 if (tv != NULL && DUK_TVAL_IS_OBJECT(tv)) {
12635 duk_hobject *h;
12636 duk_uint_fast32_t i;
12637
12638 h = DUK_TVAL_GET_OBJECT(tv);
12639 DUK_ASSERT(h != NULL);
12640
12641 /* We know _Formals is dense and all entries will be in the
12642 * array part. GC and finalizers shouldn't affect _Formals
12643 * so side effects should be fine.
12644 */
12645 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
12646 duk_tval *tv_val;
12647 duk_hstring *varname;
12648
12649 tv_val = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, h, i);
12650 DUK_ASSERT(tv_val != NULL);
12651 if (DUK_TVAL_IS_STRING(tv_val)) {
12652 /* Array is dense and contains only strings, but ASIZE may
12653 * be larger than used part and there are UNUSED entries.
12654 */
12655 varname = DUK_TVAL_GET_STRING(tv_val);
12656 DUK_ASSERT(varname != NULL);
12657 DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(varname) >= 1); /* won't be confused with terminator */
12658
12659 DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
12660 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4 + DUK_HSTRING_GET_BYTELEN(varname), p);
12661 p = duk__dump_hstring_raw(p, varname);
12662 }
12663 }
12664 } else {
12665 DUK_DD(DUK_DDPRINT("dumping function without _Formals, emit empty list"));
12666 }
12667 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 4, p);
12668 DUK_RAW_WRITE_U32_BE(p, 0); /* end of _Formals */
12669 return p;
12670}
12671
12672static duk_uint8_t *duk__dump_func(duk_context *ctx, duk_hcompfunc *func, duk_bufwriter_ctx *bw_ctx, duk_uint8_t *p) {
12673 duk_hthread *thr;
12674 duk_tval *tv, *tv_end;
12675 duk_instr_t *ins, *ins_end;
12676 duk_hobject **fn, **fn_end;
12677 duk_hstring *h_str;
12678 duk_uint32_t count_instr;
12679 duk_uint32_t tmp32;
12680 duk_uint16_t tmp16;
12681 duk_double_t d;
12682
12683 thr = (duk_hthread *) ctx;
12684 DUK_UNREF(ctx);
12685 DUK_UNREF(thr);
12686
12687 DUK_DD(DUK_DDPRINT("dumping function %p to %p: "
12688 "consts=[%p,%p[ (%ld bytes, %ld items), "
12689 "funcs=[%p,%p[ (%ld bytes, %ld items), "
12690 "code=[%p,%p[ (%ld bytes, %ld items)",
12691 (void *) func,
12692 (void *) p,
12693 (void *) DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, func),
12694 (void *) DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, func),
12695 (long) DUK_HCOMPFUNC_GET_CONSTS_SIZE(thr->heap, func),
12696 (long) DUK_HCOMPFUNC_GET_CONSTS_COUNT(thr->heap, func),
12697 (void *) DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, func),
12698 (void *) DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, func),
12699 (long) DUK_HCOMPFUNC_GET_FUNCS_SIZE(thr->heap, func),
12700 (long) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, func),
12701 (void *) DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, func),
12702 (void *) DUK_HCOMPFUNC_GET_CODE_END(thr->heap, func),
12703 (long) DUK_HCOMPFUNC_GET_CODE_SIZE(thr->heap, func),
12704 (long) DUK_HCOMPFUNC_GET_CODE_COUNT(thr->heap, func)));
12705
12706 DUK_ASSERT(DUK_USE_ESBC_MAX_BYTES <= 0x7fffffffUL); /* ensures no overflow */
12707 count_instr = (duk_uint32_t) DUK_HCOMPFUNC_GET_CODE_COUNT(thr->heap, func);
12708 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 3 * 4 + 2 * 2 + 3 * 4 + count_instr * 4, p);
12709
12710 /* Fixed header info. */
12711 tmp32 = count_instr;
12712 DUK_RAW_WRITE_U32_BE(p, tmp32);
12713 tmp32 = (duk_uint32_t) DUK_HCOMPFUNC_GET_CONSTS_COUNT(thr->heap, func);
12714 DUK_RAW_WRITE_U32_BE(p, tmp32);
12715 tmp32 = (duk_uint32_t) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, func);
12716 DUK_RAW_WRITE_U32_BE(p, tmp32);
12717 tmp16 = func->nregs;
12718 DUK_RAW_WRITE_U16_BE(p, tmp16);
12719 tmp16 = func->nargs;
12720 DUK_RAW_WRITE_U16_BE(p, tmp16);
12721#if defined(DUK_USE_DEBUGGER_SUPPORT)
12722 tmp32 = func->start_line;
12723 DUK_RAW_WRITE_U32_BE(p, tmp32);
12724 tmp32 = func->end_line;
12725 DUK_RAW_WRITE_U32_BE(p, tmp32);
12726#else
12727 DUK_RAW_WRITE_U32_BE(p, 0);
12728 DUK_RAW_WRITE_U32_BE(p, 0);
12729#endif
12730 tmp32 = DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) func); /* masks flags, only duk_hobject flags */
12731 DUK_RAW_WRITE_U32_BE(p, tmp32);
12732
12733 /* Bytecode instructions: endian conversion needed unless
12734 * platform is big endian.
12735 */
12736 ins = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, func);
12737 ins_end = DUK_HCOMPFUNC_GET_CODE_END(thr->heap, func);
12738 DUK_ASSERT((duk_size_t) (ins_end - ins) == (duk_size_t) count_instr);
12739#if defined(DUK_USE_INTEGER_BE)
12740 DUK_MEMCPY((void *) p, (const void *) ins, (size_t) (ins_end - ins));
12741 p += (size_t) (ins_end - ins);
12742#else
12743 while (ins != ins_end) {
12744 tmp32 = (duk_uint32_t) (*ins);
12745 DUK_RAW_WRITE_U32_BE(p, tmp32);
12746 ins++;
12747 }
12748#endif
12749
12750 /* Constants: variable size encoding. */
12751 tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, func);
12752 tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, func);
12753 while (tv != tv_end) {
12754 /* constants are strings or numbers now */
12755 DUK_ASSERT(DUK_TVAL_IS_STRING(tv) ||
12756 DUK_TVAL_IS_NUMBER(tv));
12757
12758 if (DUK_TVAL_IS_STRING(tv)) {
12759 h_str = DUK_TVAL_GET_STRING(tv);
12760 DUK_ASSERT(h_str != NULL);
12761 DUK_ASSERT(DUK_HSTRING_MAX_BYTELEN <= 0x7fffffffUL); /* ensures no overflow */
12762 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1 + 4 + DUK_HSTRING_GET_BYTELEN(h_str), p),
12763 *p++ = DUK__SER_STRING;
12764 p = duk__dump_hstring_raw(p, h_str);
12765 } else {
12766 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
12767 p = DUK_BW_ENSURE_RAW(thr, bw_ctx, 1 + 8, p);
12768 *p++ = DUK__SER_NUMBER;
12769 d = DUK_TVAL_GET_NUMBER(tv);
12770 DUK_RAW_WRITE_DOUBLE_BE(p, d);
12771 }
12772 tv++;
12773 }
12774
12775 /* Inner functions recursively. */
12776 fn = (duk_hobject **) DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, func);
12777 fn_end = (duk_hobject **) DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, func);
12778 while (fn != fn_end) {
12779 /* XXX: This causes recursion up to inner function depth
12780 * which is normally not an issue, e.g. mark-and-sweep uses
12781 * a recursion limiter to avoid C stack issues. Avoiding
12782 * this would mean some sort of a work list or just refusing
12783 * to serialize deep functions.
12784 */
12785 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(*fn));
12786 p = duk__dump_func(ctx, (duk_hcompfunc *) *fn, bw_ctx, p);
12787 fn++;
12788 }
12789
12790 /* Lexenv and varenv are not dumped. */
12791
12792 /* Object extra properties.
12793 *
12794 * There are some difference between function templates and functions.
12795 * For example, function templates don't have .length and nargs is
12796 * normally used to instantiate the functions.
12797 */
12798
12799 p = duk__dump_uint32_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_LENGTH, (duk_uint32_t) func->nargs);
12800#if defined(DUK_USE_FUNC_NAME_PROPERTY)
12801 p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_NAME);
12802#endif
12803#if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
12804 p = duk__dump_string_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_FILE_NAME);
12805#endif
12806#if defined(DUK_USE_PC2LINE)
12807 p = duk__dump_buffer_prop(thr, p, bw_ctx, (duk_hobject *) func, DUK_STRIDX_INT_PC2LINE);
12808#endif
12809 p = duk__dump_varmap(thr, p, bw_ctx, (duk_hobject *) func);
12810 p = duk__dump_formals(thr, p, bw_ctx, (duk_hobject *) func);
12811
12812 DUK_DD(DUK_DDPRINT("serialized function %p -> final pointer %p", (void *) func, (void *) p));
12813
12814 return p;
12815}
12816
12817/* Load a function from bytecode. The function object returned here must
12818 * match what is created by duk_js_push_closure() with respect to its flags,
12819 * properties, etc.
12820 *
12821 * NOTE: there are intentionally no input buffer length / bound checks.
12822 * Adding them would be easy but wouldn't ensure memory safety as untrusted
12823 * or broken bytecode is unsafe during execution unless the opcodes themselves
12824 * are validated (which is quite complex, especially for indirect opcodes).
12825 */
12826
12827#define DUK__ASSERT_LEFT(n) do { \
12828 DUK_ASSERT((duk_size_t) (p_end - p) >= (duk_size_t) (n)); \
12829 } while (0)
12830
12831static duk_uint8_t *duk__load_func(duk_context *ctx, duk_uint8_t *p, duk_uint8_t *p_end) {
12832 duk_hthread *thr;
12833 duk_hcompfunc *h_fun;
12834 duk_hbuffer *h_data;
12835 duk_size_t data_size;
12836 duk_uint32_t count_instr, count_const, count_funcs;
12837 duk_uint32_t n;
12838 duk_uint32_t tmp32;
12839 duk_small_uint_t const_type;
12840 duk_uint8_t *fun_data;
12841 duk_uint8_t *q;
12842 duk_idx_t idx_base;
12843 duk_tval *tv1;
12844 duk_uarridx_t arr_idx;
12845 duk_hobject *func_env;
12846 duk_bool_t need_pop;
12847
12848 /* XXX: There's some overlap with duk_js_closure() here, but
12849 * seems difficult to share code. Ensure that the final function
12850 * looks the same as created by duk_js_closure().
12851 */
12852
12853 DUK_ASSERT(ctx != NULL);
12854 thr = (duk_hthread *) ctx;
12855
12856 DUK_DD(DUK_DDPRINT("loading function, p=%p, p_end=%p", (void *) p, (void *) p_end));
12857
12858 DUK__ASSERT_LEFT(3 * 4);
12859 count_instr = DUK_RAW_READ_U32_BE(p);
12860 count_const = DUK_RAW_READ_U32_BE(p);
12861 count_funcs = DUK_RAW_READ_U32_BE(p);
12862
12863 data_size = sizeof(duk_tval) * count_const +
12864 sizeof(duk_hobject *) * count_funcs +
12865 sizeof(duk_instr_t) * count_instr;
12866
12867 DUK_DD(DUK_DDPRINT("instr=%ld, const=%ld, funcs=%ld, data_size=%ld",
12868 (long) count_instr, (long) count_const,
12869 (long) count_const, (long) data_size));
12870
12871 /* Value stack is used to ensure reachability of constants and
12872 * inner functions being loaded. Require enough space to handle
12873 * large functions correctly.
12874 */
12875 duk_require_stack(ctx, 2 + count_const + count_funcs);
12876 idx_base = duk_get_top(ctx);
12877
12878 /* Push function object, init flags etc. This must match
12879 * duk_js_push_closure() quite carefully.
12880 */
12881 h_fun = duk_push_hcompfunc(ctx);
12882 DUK_ASSERT(h_fun != NULL);
12883 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) h_fun));
12884 DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, h_fun) == NULL);
12885 DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, h_fun) == NULL);
12886 DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, h_fun) == NULL);
12887 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_fun) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
12888
12889 h_fun->nregs = DUK_RAW_READ_U16_BE(p);
12890 h_fun->nargs = DUK_RAW_READ_U16_BE(p);
12891#if defined(DUK_USE_DEBUGGER_SUPPORT)
12892 h_fun->start_line = DUK_RAW_READ_U32_BE(p);
12893 h_fun->end_line = DUK_RAW_READ_U32_BE(p);
12894#else
12895 p += 8; /* skip line info */
12896#endif
12897
12898 /* duk_hcompfunc flags; quite version specific */
12899 tmp32 = DUK_RAW_READ_U32_BE(p);
12900 DUK_HEAPHDR_SET_FLAGS((duk_heaphdr *) h_fun, tmp32); /* masks flags to only change duk_hobject flags */
12901
12902 /* standard prototype */
12903 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, &h_fun->obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
12904
12905 /* assert just a few critical flags */
12906 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h_fun) == DUK_HTYPE_OBJECT);
12907 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&h_fun->obj));
12908 DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(&h_fun->obj));
12909 DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(&h_fun->obj));
12910 DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(&h_fun->obj));
12911 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&h_fun->obj));
12912 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(&h_fun->obj));
12913 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(&h_fun->obj));
12914
12915 /* Create function 'data' buffer but don't attach it yet. */
12916 fun_data = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, data_size);
12917 DUK_ASSERT(fun_data != NULL);
12918
12919 /* Load bytecode instructions. */
12920 DUK_ASSERT(sizeof(duk_instr_t) == 4);
12921 DUK__ASSERT_LEFT(count_instr * sizeof(duk_instr_t));
12922#if defined(DUK_USE_INTEGER_BE)
12923 q = fun_data + sizeof(duk_tval) * count_const + sizeof(duk_hobject *) * count_funcs;
12924 DUK_MEMCPY((void *) q,
12925 (const void *) p,
12926 sizeof(duk_instr_t) * count_instr);
12927 p += sizeof(duk_instr_t) * count_instr;
12928#else
12929 q = fun_data + sizeof(duk_tval) * count_const + sizeof(duk_hobject *) * count_funcs;
12930 for (n = count_instr; n > 0; n--) {
12931 *((duk_instr_t *) (void *) q) = DUK_RAW_READ_U32_BE(p);
12932 q += sizeof(duk_instr_t);
12933 }
12934#endif
12935
12936 /* Load constants onto value stack but don't yet copy to buffer. */
12937 for (n = count_const; n > 0; n--) {
12938 DUK__ASSERT_LEFT(1);
12939 const_type = DUK_RAW_READ_U8(p);
12940 switch (const_type) {
12941 case DUK__SER_STRING: {
12942 p = duk__load_string_raw(ctx, p);
12943 break;
12944 }
12945 case DUK__SER_NUMBER: {
12946 /* Important to do a fastint check so that constants are
12947 * properly read back as fastints.
12948 */
12949 duk_tval tv_tmp;
12950 duk_double_t val;
12951 DUK__ASSERT_LEFT(8);
12952 val = DUK_RAW_READ_DOUBLE_BE(p);
12953 DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(&tv_tmp, val);
12954 duk_push_tval(ctx, &tv_tmp);
12955 break;
12956 }
12957 default: {
12958 goto format_error;
12959 }
12960 }
12961 }
12962
12963 /* Load inner functions to value stack, but don't yet copy to buffer. */
12964 for (n = count_funcs; n > 0; n--) {
12965 p = duk__load_func(ctx, p, p_end);
12966 if (p == NULL) {
12967 goto format_error;
12968 }
12969 }
12970
12971 /* With constants and inner functions on value stack, we can now
12972 * atomically finish the function 'data' buffer, bump refcounts,
12973 * etc.
12974 *
12975 * Here we take advantage of the value stack being just a duk_tval
12976 * array: we can just memcpy() the constants as long as we incref
12977 * them afterwards.
12978 */
12979
12980 h_data = (duk_hbuffer *) duk_known_hbuffer(ctx, idx_base + 1);
12981 DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC(h_data));
12982 DUK_HCOMPFUNC_SET_DATA(thr->heap, h_fun, h_data);
12983 DUK_HBUFFER_INCREF(thr, h_data);
12984
12985 tv1 = duk_get_tval(ctx, idx_base + 2); /* may be NULL if no constants or inner funcs */
12986 DUK_ASSERT((count_const == 0 && count_funcs == 0) || tv1 != NULL);
12987
12988 q = fun_data;
12989 if (count_const > 0) {
12990 /* Explicit zero size check to avoid NULL 'tv1'. */
12991 DUK_MEMCPY((void *) q, (const void *) tv1, sizeof(duk_tval) * count_const);
12992 for (n = count_const; n > 0; n--) {
12993 DUK_TVAL_INCREF_FAST(thr, (duk_tval *) (void *) q); /* no side effects */
12994 q += sizeof(duk_tval);
12995 }
12996 tv1 += count_const;
12997 }
12998
12999 DUK_HCOMPFUNC_SET_FUNCS(thr->heap, h_fun, (duk_hobject **) (void *) q);
13000 for (n = count_funcs; n > 0; n--) {
13001 duk_hobject *h_obj;
13002
13003 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1));
13004 h_obj = DUK_TVAL_GET_OBJECT(tv1);
13005 DUK_ASSERT(h_obj != NULL);
13006 tv1++;
13007 DUK_HOBJECT_INCREF(thr, h_obj);
13008
13009 *((duk_hobject **) (void *) q) = h_obj;
13010 q += sizeof(duk_hobject *);
13011 }
13012
13013 DUK_HCOMPFUNC_SET_BYTECODE(thr->heap, h_fun, (duk_instr_t *) (void *) q);
13014
13015 /* The function object is now reachable and refcounts are fine,
13016 * so we can pop off all the temporaries.
13017 */
13018 DUK_DDD(DUK_DDDPRINT("function is reachable, reset top; func: %!iT", duk_get_tval(ctx, idx_base)));
13019 duk_set_top(ctx, idx_base + 1);
13020
13021 /* Setup function properties. */
13022 tmp32 = DUK_RAW_READ_U32_BE(p);
13023 duk_push_u32(ctx, tmp32);
13024 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C);
13025
13026#if defined(DUK_USE_FUNC_NAME_PROPERTY)
13027 p = duk__load_string_raw(ctx, p); /* -> [ func funcname ] */
13028 func_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
13029 DUK_ASSERT(func_env != NULL);
13030 need_pop = 0;
13031 if (DUK_HOBJECT_HAS_NAMEBINDING((duk_hobject *) h_fun)) {
13032 /* Original function instance/template had NAMEBINDING.
13033 * Must create a lexical environment on loading to allow
13034 * recursive functions like 'function foo() { foo(); }'.
13035 */
13036 duk_hobject *new_env;
13037
13038 new_env = duk_push_object_helper_proto(ctx,
13039 DUK_HOBJECT_FLAG_EXTENSIBLE |
13040 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
13041 func_env);
13042 DUK_ASSERT(new_env != NULL);
13043 func_env = new_env;
13044
13045 duk_dup_m2(ctx); /* -> [ func funcname env funcname ] */
13046 duk_dup(ctx, idx_base); /* -> [ func funcname env funcname func ] */
13047 duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ func funcname env ] */
13048
13049 need_pop = 1; /* Need to pop env, but -after- updating h_fun and increfs. */
13050 }
13051 DUK_ASSERT(func_env != NULL);
13052 DUK_HCOMPFUNC_SET_LEXENV(thr->heap, h_fun, func_env);
13053 DUK_HCOMPFUNC_SET_VARENV(thr->heap, h_fun, func_env);
13054 DUK_HOBJECT_INCREF(thr, func_env);
13055 DUK_HOBJECT_INCREF(thr, func_env);
13056 if (need_pop) {
13057 duk_pop(ctx);
13058 }
13059 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
13060#endif /* DUK_USE_FUNC_NAME_PROPERTY */
13061
13062#if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
13063 p = duk__load_string_raw(ctx, p);
13064 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C);
13065#endif /* DUK_USE_FUNC_FILENAME_PROPERTY */
13066
13067 if (DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) h_fun)) {
13068 /* Restore empty external .prototype only for constructable
13069 * functions.
13070 */
13071 duk_push_object(ctx);
13072 duk_dup_m2(ctx);
13073 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* func.prototype.constructor = func */
13074 duk_compact_m1(ctx);
13075 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W);
13076 }
13077
13078#if defined(DUK_USE_PC2LINE)
13079 p = duk__load_buffer_raw(ctx, p);
13080 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_WC);
13081#endif /* DUK_USE_PC2LINE */
13082
13083 duk_push_object(ctx); /* _Varmap */
13084 for (;;) {
13085 /* XXX: awkward */
13086 p = duk__load_string_raw(ctx, p);
13087 if (duk_get_length(ctx, -1) == 0) {
13088 duk_pop(ctx);
13089 break;
13090 }
13091 tmp32 = DUK_RAW_READ_U32_BE(p);
13092 duk_push_u32(ctx, tmp32);
13093 duk_put_prop(ctx, -3);
13094 }
13095 duk_compact_m1(ctx);
13096 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE);
13097
13098 /* If _Formals wasn't present in the original function, the list
13099 * here will be empty. Same happens if _Formals was present but
13100 * had zero length. We can omit _Formals from the result if its
13101 * length is zero and matches nargs.
13102 */
13103 duk_push_array(ctx); /* _Formals */
13104 for (arr_idx = 0; ; arr_idx++) {
13105 /* XXX: awkward */
13106 p = duk__load_string_raw(ctx, p);
13107 if (duk_get_length(ctx, -1) == 0) {
13108 duk_pop(ctx);
13109 break;
13110 }
13111 duk_put_prop_index(ctx, -2, arr_idx);
13112 }
13113 if (arr_idx == 0 && h_fun->nargs == 0) {
13114 duk_pop(ctx);
13115 } else {
13116 duk_compact_m1(ctx);
13117 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE);
13118 }
13119
13120 /* Return with final function pushed on stack top. */
13121 DUK_DD(DUK_DDPRINT("final loaded function: %!iT", duk_get_tval(ctx, -1)));
13122 DUK_ASSERT_TOP(ctx, idx_base + 1);
13123 return p;
13124
13125 format_error:
13126 return NULL;
13127}
13128
13129DUK_EXTERNAL void duk_dump_function(duk_context *ctx) {
13130 duk_hthread *thr;
13131 duk_hcompfunc *func;
13132 duk_bufwriter_ctx bw_ctx_alloc;
13133 duk_bufwriter_ctx *bw_ctx = &bw_ctx_alloc;
13134 duk_uint8_t *p;
13135
13136 DUK_ASSERT(ctx != NULL);
13137 thr = (duk_hthread *) ctx;
13138
13139 /* Bound functions don't have all properties so we'd either need to
13140 * lookup the non-bound target function or reject bound functions.
13141 * For now, bound functions are rejected.
13142 */
13143 func = duk_require_hcompfunc(ctx, -1);
13144 DUK_ASSERT(func != NULL);
13145 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&func->obj));
13146
13147 /* Estimating the result size beforehand would be costly, so
13148 * start with a reasonable size and extend as needed.
13149 */
13150 DUK_BW_INIT_PUSHBUF(thr, bw_ctx, DUK__BYTECODE_INITIAL_ALLOC);
13151 p = DUK_BW_GET_PTR(thr, bw_ctx);
13152 *p++ = DUK__SER_MARKER;
13153 *p++ = DUK__SER_VERSION;
13154 p = duk__dump_func(ctx, func, bw_ctx, p);
13155 DUK_BW_SET_PTR(thr, bw_ctx, p);
13156 DUK_BW_COMPACT(thr, bw_ctx);
13157
13158 DUK_DD(DUK_DDPRINT("serialized result: %!T", duk_get_tval(ctx, -1)));
13159
13160 duk_remove_m2(ctx); /* [ ... func buf ] -> [ ... buf ] */
13161}
13162
13163DUK_EXTERNAL void duk_load_function(duk_context *ctx) {
13164 duk_hthread *thr;
13165 duk_uint8_t *p_buf, *p, *p_end;
13166 duk_size_t sz;
13167
13168 DUK_ASSERT(ctx != NULL);
13169 thr = (duk_hthread *) ctx;
13170 DUK_UNREF(ctx);
13171
13172 p_buf = (duk_uint8_t *) duk_require_buffer(ctx, -1, &sz);
13173 DUK_ASSERT(p_buf != NULL);
13174
13175 /* The caller is responsible for being sure that bytecode being loaded
13176 * is valid and trusted. Invalid bytecode can cause memory unsafe
13177 * behavior directly during loading or later during bytecode execution
13178 * (instruction validation would be quite complex to implement).
13179 *
13180 * This signature check is the only sanity check for detecting
13181 * accidental invalid inputs. The initial 0xFF byte ensures no
13182 * ordinary string will be accepted by accident.
13183 */
13184 p = p_buf;
13185 p_end = p_buf + sz;
13186 if (sz < 2 || p[0] != DUK__SER_MARKER || p[1] != DUK__SER_VERSION) {
13187 goto format_error;
13188 }
13189 p += 2;
13190
13191 p = duk__load_func(ctx, p, p_end);
13192 if (p == NULL) {
13193 goto format_error;
13194 }
13195
13196 duk_remove_m2(ctx); /* [ ... buf func ] -> [ ... func ] */
13197 return;
13198
13199 format_error:
13200 DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED);
13201}
13202
13203#else /* DUK_USE_BYTECODE_DUMP_SUPPORT */
13204
13205DUK_EXTERNAL void duk_dump_function(duk_context *ctx) {
13206 DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx);
13207}
13208
13209DUK_EXTERNAL void duk_load_function(duk_context *ctx) {
13210 DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx);
13211}
13212
13213#endif /* DUK_USE_BYTECODE_DUMP_SUPPORT */
13214
13215/* automatic undefs */
13216#undef DUK__ASSERT_LEFT
13217#undef DUK__BYTECODE_INITIAL_ALLOC
13218#undef DUK__SER_MARKER
13219#undef DUK__SER_NUMBER
13220#undef DUK__SER_STRING
13221#undef DUK__SER_VERSION
13222/*
13223 * Calls.
13224 *
13225 * Protected variants should avoid ever throwing an error.
13226 */
13227
13228/* #include duk_internal.h -> already included */
13229
13230/* Prepare value stack for a method call through an object property.
13231 * May currently throw an error e.g. when getting the property.
13232 */
13233DUK_LOCAL void duk__call_prop_prep_stack(duk_context *ctx, duk_idx_t normalized_obj_idx, duk_idx_t nargs) {
13234 DUK_ASSERT_CTX_VALID(ctx);
13235
13236 DUK_DDD(DUK_DDDPRINT("duk__call_prop_prep_stack, normalized_obj_idx=%ld, nargs=%ld, stacktop=%ld",
13237 (long) normalized_obj_idx, (long) nargs, (long) duk_get_top(ctx)));
13238
13239 /* [... key arg1 ... argN] */
13240
13241 /* duplicate key */
13242 duk_dup(ctx, -nargs - 1); /* Note: -nargs alone would fail for nargs == 0, this is OK */
13243 duk_get_prop(ctx, normalized_obj_idx);
13244
13245 DUK_DDD(DUK_DDDPRINT("func: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
13246
13247 /* [... key arg1 ... argN func] */
13248
13249 duk_replace(ctx, -nargs - 2);
13250
13251 /* [... func arg1 ... argN] */
13252
13253 duk_dup(ctx, normalized_obj_idx);
13254 duk_insert(ctx, -nargs - 1);
13255
13256 /* [... func this arg1 ... argN] */
13257}
13258
13259DUK_EXTERNAL void duk_call(duk_context *ctx, duk_idx_t nargs) {
13260 duk_hthread *thr = (duk_hthread *) ctx;
13261 duk_small_uint_t call_flags;
13262 duk_idx_t idx_func;
13263
13264 DUK_ASSERT_CTX_VALID(ctx);
13265 DUK_ASSERT(thr != NULL);
13266
13267 idx_func = duk_get_top(ctx) - nargs - 1;
13268 if (idx_func < 0 || nargs < 0) {
13269 /* note that we can't reliably pop anything here */
13270 DUK_ERROR_TYPE_INVALID_ARGS(thr);
13271 }
13272
13273 /* XXX: awkward; we assume there is space for this, overwrite
13274 * directly instead?
13275 */
13276 duk_push_undefined(ctx);
13277 duk_insert(ctx, idx_func + 1);
13278
13279 call_flags = 0; /* not protected, respect reclimit, not constructor */
13280
13281 duk_handle_call_unprotected(thr, /* thread */
13282 nargs, /* num_stack_args */
13283 call_flags); /* call_flags */
13284}
13285
13286DUK_EXTERNAL void duk_call_method(duk_context *ctx, duk_idx_t nargs) {
13287 duk_hthread *thr = (duk_hthread *) ctx;
13288 duk_small_uint_t call_flags;
13289 duk_idx_t idx_func;
13290
13291 DUK_ASSERT_CTX_VALID(ctx);
13292 DUK_ASSERT(thr != NULL);
13293
13294 idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */
13295 if (idx_func < 0 || nargs < 0) {
13296 /* note that we can't reliably pop anything here */
13297 DUK_ERROR_TYPE_INVALID_ARGS(thr);
13298 }
13299
13300 call_flags = 0; /* not protected, respect reclimit, not constructor */
13301
13302 duk_handle_call_unprotected(thr, /* thread */
13303 nargs, /* num_stack_args */
13304 call_flags); /* call_flags */
13305}
13306
13307DUK_EXTERNAL void duk_call_prop(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t nargs) {
13308 /*
13309 * XXX: if duk_handle_call() took values through indices, this could be
13310 * made much more sensible. However, duk_handle_call() needs to fudge
13311 * the 'this' and 'func' values to handle bound function chains, which
13312 * is now done "in-place", so this is not a trivial change.
13313 */
13314
13315 DUK_ASSERT_CTX_VALID(ctx);
13316
13317 obj_idx = duk_require_normalize_index(ctx, obj_idx); /* make absolute */
13318
13319 duk__call_prop_prep_stack(ctx, obj_idx, nargs);
13320
13321 duk_call_method(ctx, nargs);
13322}
13323
13324DUK_EXTERNAL duk_int_t duk_pcall(duk_context *ctx, duk_idx_t nargs) {
13325 duk_hthread *thr = (duk_hthread *) ctx;
13326 duk_small_uint_t call_flags;
13327 duk_idx_t idx_func;
13328 duk_int_t rc;
13329
13330 DUK_ASSERT_CTX_VALID(ctx);
13331 DUK_ASSERT(thr != NULL);
13332
13333 idx_func = duk_get_top(ctx) - nargs - 1; /* must work for nargs <= 0 */
13334 if (idx_func < 0 || nargs < 0) {
13335 /* We can't reliably pop anything here because the stack input
13336 * shape is incorrect. So we throw an error; if the caller has
13337 * no catch point for this, a fatal error will occur. Another
13338 * alternative would be to just return an error. But then the
13339 * stack would be in an unknown state which might cause some
13340 * very hard to diagnose problems later on. Also note that even
13341 * if we did not throw an error here, the underlying call handler
13342 * might STILL throw an out-of-memory error or some other internal
13343 * fatal error.
13344 */
13345 DUK_ERROR_TYPE_INVALID_ARGS(thr);
13346 return DUK_EXEC_ERROR; /* unreachable */
13347 }
13348
13349 /* awkward; we assume there is space for this */
13350 duk_push_undefined(ctx);
13351 duk_insert(ctx, idx_func + 1);
13352
13353 call_flags = 0; /* respect reclimit, not constructor */
13354
13355 rc = duk_handle_call_protected(thr, /* thread */
13356 nargs, /* num_stack_args */
13357 call_flags); /* call_flags */
13358
13359 return rc;
13360}
13361
13362DUK_EXTERNAL duk_int_t duk_pcall_method(duk_context *ctx, duk_idx_t nargs) {
13363 duk_hthread *thr = (duk_hthread *) ctx;
13364 duk_small_uint_t call_flags;
13365 duk_idx_t idx_func;
13366 duk_int_t rc;
13367
13368 DUK_ASSERT_CTX_VALID(ctx);
13369 DUK_ASSERT(thr != NULL);
13371 idx_func = duk_get_top(ctx) - nargs - 2; /* must work for nargs <= 0 */
13372 if (idx_func < 0 || nargs < 0) {
13373 /* See comments in duk_pcall(). */
13374 DUK_ERROR_TYPE_INVALID_ARGS(thr);
13375 return DUK_EXEC_ERROR; /* unreachable */
13376 }
13377
13378 call_flags = 0; /* respect reclimit, not constructor */
13379
13380 rc = duk_handle_call_protected(thr, /* thread */
13381 nargs, /* num_stack_args */
13382 call_flags); /* call_flags */
13383
13384 return rc;
13385}
13386
13387struct duk__pcall_prop_args {
13388 duk_idx_t obj_idx;
13389 duk_idx_t nargs;
13390};
13392
13393DUK_LOCAL duk_ret_t duk__pcall_prop_raw(duk_context *ctx, void *udata) {
13394 duk_idx_t obj_idx;
13395 duk_idx_t nargs;
13397
13398 DUK_ASSERT_CTX_VALID(ctx);
13399 DUK_ASSERT(udata != NULL);
13400
13401 args = (duk__pcall_prop_args *) udata;
13402 obj_idx = args->obj_idx;
13403 nargs = args->nargs;
13404
13405 obj_idx = duk_require_normalize_index(ctx, obj_idx); /* make absolute */
13406 duk__call_prop_prep_stack(ctx, obj_idx, nargs);
13407 duk_call_method(ctx, nargs);
13408 return 1;
13409}
13410
13411DUK_EXTERNAL duk_int_t duk_pcall_prop(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t nargs) {
13413
13414 /*
13415 * Must be careful to catch errors related to value stack manipulation
13416 * and property lookup, not just the call itself.
13417 */
13418
13419 DUK_ASSERT_CTX_VALID(ctx);
13420
13421 args.obj_idx = obj_idx;
13422 args.nargs = nargs;
13423
13424 /* Inputs: explicit arguments (nargs), +1 for key. If the value stack
13425 * does not contain enough args, an error is thrown; this matches
13426 * behavior of the other protected call API functions.
13427 */
13428 return duk_safe_call(ctx, duk__pcall_prop_raw, (void *) &args /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/);
13429}
13430
13431DUK_EXTERNAL duk_int_t duk_safe_call(duk_context *ctx, duk_safe_call_function func, void *udata, duk_idx_t nargs, duk_idx_t nrets) {
13432 duk_hthread *thr = (duk_hthread *) ctx;
13433 duk_int_t rc;
13434
13435 DUK_ASSERT_CTX_VALID(ctx);
13436 DUK_ASSERT(thr != NULL);
13437
13438 if (duk_get_top(ctx) < nargs || nrets < 0) {
13439 /* See comments in duk_pcall(). */
13440 DUK_ERROR_TYPE_INVALID_ARGS(thr);
13441 return DUK_EXEC_ERROR; /* unreachable */
13442 }
13443
13444 rc = duk_handle_safe_call(thr, /* thread */
13445 func, /* func */
13446 udata, /* udata */
13447 nargs, /* num_stack_args */
13448 nrets); /* num_stack_res */
13449
13450 return rc;
13451}
13452
13453DUK_EXTERNAL void duk_new(duk_context *ctx, duk_idx_t nargs) {
13454 /*
13455 * There are two [[Construct]] operations in the specification:
13456 *
13457 * - E5 Section 13.2.2: for Function objects
13458 * - E5 Section 15.3.4.5.2: for "bound" Function objects
13459 *
13460 * The chain of bound functions is resolved in Section 15.3.4.5.2,
13461 * with arguments "piling up" until the [[Construct]] internal
13462 * method is called on the final, actual Function object. Note
13463 * that the "prototype" property is looked up *only* from the
13464 * final object, *before* calling the constructor.
13465 *
13466 * Currently we follow the bound function chain here to get the
13467 * "prototype" property value from the final, non-bound function.
13468 * However, we let duk_handle_call() handle the argument "piling"
13469 * when the constructor is called. The bound function chain is
13470 * thus now processed twice.
13471 *
13472 * When constructing new Array instances, an unnecessary object is
13473 * created and discarded now: the standard [[Construct]] creates an
13474 * object, and calls the Array constructor. The Array constructor
13475 * returns an Array instance, which is used as the result value for
13476 * the "new" operation; the object created before the Array constructor
13477 * call is discarded.
13478 *
13479 * This would be easy to fix, e.g. by knowing that the Array constructor
13480 * will always create a replacement object and skip creating the fallback
13481 * object in that case.
13482 *
13483 * Note: functions called via "new" need to know they are called as a
13484 * constructor. For instance, built-in constructors behave differently
13485 * depending on how they are called.
13486 */
13487
13488 /* XXX: merge this with duk_js_call.c, as this function implements
13489 * core semantics (or perhaps merge the two files altogether).
13490 */
13491
13492 duk_hthread *thr = (duk_hthread *) ctx;
13493 duk_hobject *proto;
13494 duk_hobject *cons;
13495 duk_hobject *fallback;
13496 duk_idx_t idx_cons;
13497 duk_small_uint_t call_flags;
13498
13499 DUK_ASSERT_CTX_VALID(ctx);
13500
13501 /* [... constructor arg1 ... argN] */
13502
13503 idx_cons = duk_require_normalize_index(ctx, -nargs - 1);
13504
13505 DUK_DDD(DUK_DDDPRINT("top=%ld, nargs=%ld, idx_cons=%ld",
13506 (long) duk_get_top(ctx), (long) nargs, (long) idx_cons));
13507
13508 /* XXX: code duplication */
13509
13510 /*
13511 * Figure out the final, non-bound constructor, to get "prototype"
13512 * property.
13513 */
13514
13515 duk_dup(ctx, idx_cons);
13516 for (;;) {
13517 duk_tval *tv;
13518 tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
13519 DUK_ASSERT(tv != NULL);
13520
13521 if (DUK_TVAL_IS_OBJECT(tv)) {
13522 cons = DUK_TVAL_GET_OBJECT(tv);
13523 DUK_ASSERT(cons != NULL);
13524 if (!DUK_HOBJECT_IS_CALLABLE(cons) || !DUK_HOBJECT_HAS_CONSTRUCTABLE(cons)) {
13525 /* Checking callability of the immediate target
13526 * is important, same for constructability.
13527 * Checking it for functions down the bound
13528 * function chain is not strictly necessary
13529 * because .bind() should normally reject them.
13530 * But it's good to check anyway because it's
13531 * technically possible to edit the bound function
13532 * chain via internal keys.
13533 */
13534 goto not_constructable;
13535 }
13536 if (!DUK_HOBJECT_HAS_BOUNDFUNC(cons)) {
13537 break;
13538 }
13539 } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
13540 /* Lightfuncs cannot be bound. */
13541 break;
13542 } else {
13543 /* Anything else is not constructable. */
13544 goto not_constructable;
13545 }
13546 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_TARGET); /* -> [... cons target] */
13547 duk_remove_m2(ctx); /* -> [... target] */
13548 }
13549 DUK_ASSERT(duk_is_callable(ctx, -1));
13550 DUK_ASSERT(duk_is_lightfunc(ctx, -1) ||
13551 (duk_get_hobject(ctx, -1) != NULL && !DUK_HOBJECT_HAS_BOUNDFUNC(duk_get_hobject(ctx, -1))));
13552
13553 /* [... constructor arg1 ... argN final_cons] */
13554
13555 /*
13556 * Create "fallback" object to be used as the object instance,
13557 * unless the constructor returns a replacement value.
13558 * Its internal prototype needs to be set based on "prototype"
13559 * property of the constructor.
13560 */
13561
13562 duk_push_object(ctx); /* class Object, extensible */
13563
13564 /* [... constructor arg1 ... argN final_cons fallback] */
13565
13566 duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_PROTOTYPE);
13567 proto = duk_get_hobject(ctx, -1);
13568 if (!proto) {
13569 DUK_DDD(DUK_DDDPRINT("constructor has no 'prototype' property, or value not an object "
13570 "-> leave standard Object prototype as fallback prototype"));
13571 } else {
13572 DUK_DDD(DUK_DDDPRINT("constructor has 'prototype' property with object value "
13573 "-> set fallback prototype to that value: %!iO", (duk_heaphdr *) proto));
13574 fallback = duk_get_hobject(ctx, -2);
13575 DUK_ASSERT(fallback != NULL);
13576 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, fallback, proto);
13577 }
13578 duk_pop(ctx);
13579
13580 /* [... constructor arg1 ... argN final_cons fallback] */
13581
13582 /*
13583 * Manipulate callstack for the call.
13584 */
13585
13586 duk_dup_top(ctx);
13587 duk_insert(ctx, idx_cons + 1); /* use fallback as 'this' value */
13588 duk_insert(ctx, idx_cons); /* also stash it before constructor,
13589 * in case we need it (as the fallback value)
13590 */
13591 duk_pop(ctx); /* pop final_cons */
13592
13593
13594 /* [... fallback constructor fallback(this) arg1 ... argN];
13595 * Note: idx_cons points to first 'fallback', not 'constructor'.
13596 */
13597
13598 DUK_DDD(DUK_DDDPRINT("before call, idx_cons+1 (constructor) -> %!T, idx_cons+2 (fallback/this) -> %!T, "
13599 "nargs=%ld, top=%ld",
13600 (duk_tval *) duk_get_tval(ctx, idx_cons + 1),
13601 (duk_tval *) duk_get_tval(ctx, idx_cons + 2),
13602 (long) nargs,
13603 (long) duk_get_top(ctx)));
13604
13605 /*
13606 * Call the constructor function (called in "constructor mode").
13607 */
13608
13609 call_flags = DUK_CALL_FLAG_CONSTRUCTOR_CALL; /* not protected, respect reclimit, is a constructor call */
13610
13611 duk_handle_call_unprotected(thr, /* thread */
13612 nargs, /* num_stack_args */
13613 call_flags); /* call_flags */
13614
13615 /* [... fallback retval] */
13616
13617 DUK_DDD(DUK_DDDPRINT("constructor call finished, fallback=%!iT, retval=%!iT",
13618 (duk_tval *) duk_get_tval(ctx, -2),
13619 (duk_tval *) duk_get_tval(ctx, -1)));
13620
13621 /*
13622 * Determine whether to use the constructor return value as the created
13623 * object instance or not.
13624 */
13625
13626 if (duk_check_type_mask(ctx, -1, DUK_TYPE_MASK_OBJECT |
13627 DUK_TYPE_MASK_BUFFER |
13628 DUK_TYPE_MASK_LIGHTFUNC)) {
13629 duk_remove_m2(ctx);
13630 } else {
13631 duk_pop(ctx);
13632 }
13633
13634 /*
13635 * Augment created errors upon creation (not when they are thrown or
13636 * rethrown). __FILE__ and __LINE__ are not desirable here; the call
13637 * stack reflects the caller which is correct.
13638 */
13639
13640#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
13641 duk_hthread_sync_currpc(thr);
13642 duk_err_augment_error_create(thr, thr, NULL, 0, 1 /*noblame_fileline*/);
13643#endif
13644
13645 /* [... retval] */
13646
13647 return;
13648
13649 not_constructable:
13650#if defined(DUK_USE_VERBOSE_ERRORS)
13651#if defined(DUK_USE_PARANOID_ERRORS)
13652 DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not constructable", duk_get_type_name(ctx, -1));
13653#else
13654 DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not constructable", duk_push_string_readable(ctx, -1));
13655#endif
13656#else
13657 DUK_ERROR_TYPE(thr, "not constructable");
13658#endif
13659}
13660
13661DUK_LOCAL duk_ret_t duk__pnew_helper(duk_context *ctx, void *udata) {
13662 duk_idx_t nargs;
13663
13664 DUK_ASSERT(udata != NULL);
13665 nargs = *((duk_idx_t *) udata);
13666
13667 duk_new(ctx, nargs);
13668 return 1;
13669}
13670
13671DUK_EXTERNAL duk_int_t duk_pnew(duk_context *ctx, duk_idx_t nargs) {
13672 duk_int_t rc;
13673
13674 DUK_ASSERT_CTX_VALID(ctx);
13675
13676 /* For now, just use duk_safe_call() to wrap duk_new(). We can't
13677 * simply use a protected duk_handle_call() because there's post
13678 * processing which might throw. It should be possible to ensure
13679 * the post processing never throws (except in internal errors and
13680 * out of memory etc which are always allowed) and then remove this
13681 * wrapper.
13682 */
13683
13684 rc = duk_safe_call(ctx, duk__pnew_helper, (void *) &nargs /*udata*/, nargs + 1 /*nargs*/, 1 /*nrets*/);
13685 return rc;
13686}
13687
13688DUK_EXTERNAL duk_bool_t duk_is_constructor_call(duk_context *ctx) {
13689 duk_hthread *thr = (duk_hthread *) ctx;
13690 duk_activation *act;
13691
13692 DUK_ASSERT_CTX_VALID(ctx);
13693 DUK_ASSERT(thr != NULL);
13694 DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
13695
13696 act = duk_hthread_get_current_activation(thr);
13697 DUK_ASSERT(act != NULL); /* because callstack_top > 0 */
13698 return ((act->flags & DUK_ACT_FLAG_CONSTRUCT) != 0 ? 1 : 0);
13699}
13700
13701/* XXX: Make this obsolete by adding a function flag for rejecting a
13702 * non-constructor call automatically?
13703 */
13704DUK_INTERNAL void duk_require_constructor_call(duk_context *ctx) {
13705 if (!duk_is_constructor_call(ctx)) {
13706 DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_CONSTRUCT_ONLY);
13707 }
13708}
13709
13710DUK_EXTERNAL duk_bool_t duk_is_strict_call(duk_context *ctx) {
13711 duk_hthread *thr = (duk_hthread *) ctx;
13712 duk_activation *act;
13713
13714 /* For user code this could just return 1 (strict) always
13715 * because all Duktape/C functions are considered strict,
13716 * and strict is also the default when nothing is running.
13717 * However, Duktape may call this function internally when
13718 * the current activation is an Ecmascript function, so
13719 * this cannot be replaced by a 'return 1' without fixing
13720 * the internal call sites.
13721 */
13722
13723 DUK_ASSERT_CTX_VALID(ctx);
13724 DUK_ASSERT(thr != NULL);
13725 DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
13726
13727 act = duk_hthread_get_current_activation(thr);
13728 if (act == NULL) {
13729 /* Strict by default. */
13730 return 1;
13731 }
13732 return ((act->flags & DUK_ACT_FLAG_STRICT) != 0 ? 1 : 0);
13733}
13734
13735/*
13736 * Duktape/C function magic
13737 */
13738
13739DUK_EXTERNAL duk_int_t duk_get_current_magic(duk_context *ctx) {
13740 duk_hthread *thr = (duk_hthread *) ctx;
13741 duk_activation *act;
13742 duk_hobject *func;
13743
13744 DUK_ASSERT_CTX_VALID(ctx);
13745 DUK_ASSERT(thr != NULL);
13746 DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
13747
13748 act = duk_hthread_get_current_activation(thr);
13749 if (act) {
13750 func = DUK_ACT_GET_FUNC(act);
13751 if (!func) {
13752 duk_tval *tv = &act->tv_func;
13753 duk_small_uint_t lf_flags;
13754 lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
13755 return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
13756 }
13757 DUK_ASSERT(func != NULL);
13758
13759 if (DUK_HOBJECT_IS_NATFUNC(func)) {
13760 duk_hnatfunc *nf = (duk_hnatfunc *) func;
13761 return (duk_int_t) nf->magic;
13762 }
13763 }
13764 return 0;
13765}
13766
13767DUK_EXTERNAL duk_int_t duk_get_magic(duk_context *ctx, duk_idx_t idx) {
13768 duk_hthread *thr = (duk_hthread *) ctx;
13769 duk_tval *tv;
13770 duk_hobject *h;
13771
13772 DUK_ASSERT_CTX_VALID(ctx);
13773
13774 tv = duk_require_tval(ctx, idx);
13775 if (DUK_TVAL_IS_OBJECT(tv)) {
13776 h = DUK_TVAL_GET_OBJECT(tv);
13777 DUK_ASSERT(h != NULL);
13778 if (!DUK_HOBJECT_HAS_NATFUNC(h)) {
13779 goto type_error;
13780 }
13781 return (duk_int_t) ((duk_hnatfunc *) h)->magic;
13782 } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
13783 duk_small_uint_t lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
13784 return (duk_int_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
13785 }
13786
13787 /* fall through */
13788 type_error:
13789 DUK_ERROR_TYPE(thr, DUK_STR_UNEXPECTED_TYPE);
13790 return 0;
13791}
13792
13793DUK_EXTERNAL void duk_set_magic(duk_context *ctx, duk_idx_t idx, duk_int_t magic) {
13794 duk_hnatfunc *nf;
13795
13796 DUK_ASSERT_CTX_VALID(ctx);
13797
13798 nf = duk_require_hnatfunc(ctx, idx);
13799 DUK_ASSERT(nf != NULL);
13800 nf->magic = (duk_int16_t) magic;
13801}
13802
13803/*
13804 * Misc helpers
13805 */
13806
13807DUK_INTERNAL void duk_resolve_nonbound_function(duk_context *ctx) {
13808 duk_uint_t sanity;
13809 duk_tval *tv;
13810
13811 sanity = DUK_HOBJECT_BOUND_CHAIN_SANITY;
13812 do {
13813 tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
13814 if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
13815 /* Lightweight function: never bound, so terminate. */
13816 break;
13817 } else if (DUK_TVAL_IS_OBJECT(tv)) {
13818 duk_hobject *func;
13819
13820 func = DUK_TVAL_GET_OBJECT(tv);
13821 DUK_ASSERT(func != NULL);
13822 if (!DUK_HOBJECT_IS_CALLABLE(func) || !DUK_HOBJECT_HAS_BOUNDFUNC(func)) {
13823 break;
13824 }
13825 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_TARGET);
13826 duk_replace(ctx, -2);
13827 } else {
13828 break;
13829 }
13830 } while (--sanity > 0);
13831}
13832/*
13833 * Encoding and decoding basic formats: hex, base64.
13834 *
13835 * These are in-place operations which may allow an optimized implementation.
13836 *
13837 * Base-64: https://tools.ietf.org/html/rfc4648#section-4
13838 */
13839
13840/* #include duk_internal.h -> already included */
13841
13842/* Shared handling for encode/decode argument. Fast path handling for
13843 * buffer and string values because they're the most common. In particular,
13844 * avoid creating a temporary string or buffer when possible.
13845 */
13846DUK_LOCAL const duk_uint8_t *duk__prep_codec_arg(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len) {
13847 void *ptr;
13848 duk_bool_t isbuffer;
13849
13850 DUK_ASSERT(duk_is_valid_index(ctx, idx)); /* checked by caller */
13851
13852 ptr = duk_get_buffer_data_raw(ctx, idx, out_len, 0 /*throw_flag*/, &isbuffer);
13853 if (isbuffer) {
13854 DUK_ASSERT(*out_len == 0 || ptr != NULL);
13855 return (const duk_uint8_t *) ptr;
13856 }
13857 return (const duk_uint8_t *) duk_to_lstring(ctx, idx, out_len);
13858}
13859
13860#if defined(DUK_USE_BASE64_FASTPATH)
13861DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) {
13862 duk_uint_t t;
13863 duk_size_t n_full, n_full3, n_final;
13864 const duk_uint8_t *src_end_fast;
13865
13866 n_full = srclen / 3; /* full 3-byte -> 4-char conversions */
13867 n_full3 = n_full * 3;
13868 n_final = srclen - n_full3;
13869 DUK_ASSERT_DISABLE(n_final >= 0);
13870 DUK_ASSERT(n_final <= 2);
13871
13872 src_end_fast = src + n_full3;
13873 while (DUK_UNLIKELY(src != src_end_fast)) {
13874 t = (duk_uint_t) (*src++);
13875 t = (t << 8) + (duk_uint_t) (*src++);
13876 t = (t << 8) + (duk_uint_t) (*src++);
13877
13878 *dst++ = duk_base64_enctab[t >> 18];
13879 *dst++ = duk_base64_enctab[(t >> 12) & 0x3f];
13880 *dst++ = duk_base64_enctab[(t >> 6) & 0x3f];
13881 *dst++ = duk_base64_enctab[t & 0x3f];
13882
13883#if 0 /* Tested: not faster on x64 */
13884 /* aaaaaabb bbbbcccc ccdddddd */
13885 dst[0] = duk_base64_enctab[(src[0] >> 2) & 0x3f];
13886 dst[1] = duk_base64_enctab[((src[0] << 4) & 0x30) | ((src[1] >> 4) & 0x0f)];
13887 dst[2] = duk_base64_enctab[((src[1] << 2) & 0x3f) | ((src[2] >> 6) & 0x03)];
13888 dst[3] = duk_base64_enctab[src[2] & 0x3f];
13889 src += 3; dst += 4;
13890#endif
13891 }
13892
13893 switch (n_final) {
13894 /* case 0: nop */
13895 case 1: {
13896 /* XX== */
13897 t = (duk_uint_t) (*src++);
13898 *dst++ = duk_base64_enctab[t >> 2]; /* XXXXXX-- */
13899 *dst++ = duk_base64_enctab[(t << 4) & 0x3f]; /* ------XX */
13900 *dst++ = DUK_ASC_EQUALS;
13901 *dst++ = DUK_ASC_EQUALS;
13902 break;
13903 }
13904 case 2: {
13905 /* XXX= */
13906 t = (duk_uint_t) (*src++);
13907 t = (t << 8) + (duk_uint_t) (*src++);
13908 *dst++ = duk_base64_enctab[t >> 10]; /* XXXXXX-- -------- */
13909 *dst++ = duk_base64_enctab[(t >> 4) & 0x3f]; /* ------XX XXXX---- */
13910 *dst++ = duk_base64_enctab[(t << 2) & 0x3f]; /* -------- ----XXXX */
13911 *dst++ = DUK_ASC_EQUALS;
13912 break;
13913 }
13914 }
13915}
13916#else /* DUK_USE_BASE64_FASTPATH */
13917DUK_LOCAL void duk__base64_encode_helper(const duk_uint8_t *src, duk_size_t srclen, duk_uint8_t *dst) {
13918 duk_small_uint_t i, snip;
13919 duk_uint_t t;
13920 duk_uint_fast8_t x, y;
13921 const duk_uint8_t *src_end;
13922
13923 src_end = src + srclen;
13924
13925 while (src < src_end) {
13926 /* read 3 bytes into 't', padded by zero */
13927 snip = 4;
13928 t = 0;
13929 for (i = 0; i < 3; i++) {
13930 t = t << 8;
13931 if (src >= src_end) {
13932 snip--;
13933 } else {
13934 t += (duk_uint_t) (*src++);
13935 }
13936 }
13937
13938 /*
13939 * Missing bytes snip base64 example
13940 * 0 4 XXXX
13941 * 1 3 XXX=
13942 * 2 2 XX==
13943 */
13944
13945 DUK_ASSERT(snip >= 2 && snip <= 4);
13946
13947 for (i = 0; i < 4; i++) {
13948 x = (duk_uint_fast8_t) ((t >> 18) & 0x3f);
13949 t = t << 6;
13950
13951 /* A straightforward 64-byte lookup would be faster
13952 * and cleaner, but this is shorter.
13953 */
13954 if (i >= snip) {
13955 y = '=';
13956 } else if (x <= 25) {
13957 y = x + 'A';
13958 } else if (x <= 51) {
13959 y = x - 26 + 'a';
13960 } else if (x <= 61) {
13961 y = x - 52 + '0';
13962 } else if (x == 62) {
13963 y = '+';
13964 } else {
13965 y = '/';
13966 }
13967
13968 *dst++ = (duk_uint8_t) y;
13969 }
13970 }
13971}
13972#endif /* DUK_USE_BASE64_FASTPATH */
13973
13974#if defined(DUK_USE_BASE64_FASTPATH)
13975DUK_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) {
13976 duk_int_t x;
13977 duk_int_t t;
13978 duk_small_uint_t n_equal;
13979 duk_small_uint_t n_chars;
13980 const duk_uint8_t *src_end;
13981 const duk_uint8_t *src_end_safe;
13982
13983 src_end = src + srclen;
13984 src_end_safe = src_end - 4; /* if 'src < src_end_safe', safe to read 4 bytes */
13985
13986 /* Innermost fast path processes 4 valid base-64 characters at a time
13987 * but bails out on whitespace, padding chars ('=') and invalid chars.
13988 * Once the slow path segment has been processed, we return to the
13989 * inner fast path again. This handles e.g. base64 with newlines
13990 * reasonably well because the majority of a line is in the fast path.
13991 */
13992 for (;;) {
13993 /* Fast path, handle units with just actual encoding characters. */
13994
13995 while (src <= src_end_safe) {
13996 /* The lookup byte is intentionally sign extended to (at least)
13997 * 32 bits and then ORed. This ensures that is at least 1 byte
13998 * is negative, the highest bit of 't' will be set at the end
13999 * and we don't need to check every byte.
14000 */
14001 DUK_DDD(DUK_DDDPRINT("fast loop: src=%p, src_end_safe=%p, src_end=%p",
14002 (const void *) src, (const void *) src_end_safe, (const void *) src_end));
14003
14004 t = (duk_int_t) duk_base64_dectab[*src++];
14005 t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++];
14006 t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++];
14007 t = (t << 6) | (duk_int_t) duk_base64_dectab[*src++];
14008
14009 if (DUK_UNLIKELY(t < 0)) {
14010 DUK_DDD(DUK_DDDPRINT("fast loop unit was not clean, process one slow path unit"));
14011 src -= 4;
14012 break;
14013 }
14014
14015 DUK_ASSERT(t <= 0xffffffL);
14016 DUK_ASSERT((t >> 24) == 0);
14017 *dst++ = (duk_uint8_t) (t >> 16);
14018 *dst++ = (duk_uint8_t) ((t >> 8) & 0xff);
14019 *dst++ = (duk_uint8_t) (t & 0xff);
14020 }
14021
14022 /* Handle one slow path unit (or finish if we're done). */
14023
14024 n_equal = 0;
14025 n_chars = 0;
14026 t = 0;
14027 for (;;) {
14028 DUK_DDD(DUK_DDDPRINT("slow loop: src=%p, src_end=%p, n_chars=%ld, n_equal=%ld, t=%ld",
14029 (const void *) src, (const void *) src_end, (long) n_chars, (long) n_equal, (long) t));
14030
14031 if (DUK_UNLIKELY(src >= src_end)) {
14032 goto done; /* two level break */
14033 }
14034
14035 x = duk_base64_dectab[*src++];
14036 if (DUK_UNLIKELY(x < 0)) {
14037 if (x == -2) {
14038 continue; /* allowed ascii whitespace */
14039 } else if (x == -3) {
14040 n_equal++;
14041 t <<= 6;
14042 } else {
14043 DUK_ASSERT(x == -1);
14044 goto error;
14045 }
14046 } else {
14047 DUK_ASSERT(x >= 0 && x <= 63);
14048 if (n_equal > 0) {
14049 /* Don't allow actual chars after equal sign. */
14050 goto error;
14051 }
14052 t = (t << 6) + x;
14053 }
14054
14055 if (DUK_UNLIKELY(n_chars == 3)) {
14056 /* Emit 3 bytes and backtrack if there was padding. There's
14057 * always space for the whole 3 bytes so no check needed.
14058 */
14059 DUK_ASSERT(t <= 0xffffffL);
14060 DUK_ASSERT((t >> 24) == 0);
14061 *dst++ = (duk_uint8_t) (t >> 16);
14062 *dst++ = (duk_uint8_t) ((t >> 8) & 0xff);
14063 *dst++ = (duk_uint8_t) (t & 0xff);
14064
14065 if (DUK_UNLIKELY(n_equal > 0)) {
14066 DUK_ASSERT(n_equal <= 4);
14067
14068 /* There may be whitespace between the equal signs. */
14069 if (n_equal == 1) {
14070 /* XXX= */
14071 dst -= 1;
14072 } else if (n_equal == 2) {
14073 /* XX== */
14074 dst -= 2;
14075 } else {
14076 goto error; /* invalid padding */
14077 }
14078
14079 /* Continue parsing after padding, allows concatenated,
14080 * padded base64.
14081 */
14082 }
14083 break; /* back to fast loop */
14084 } else {
14085 n_chars++;
14086 }
14087 }
14088 }
14089 done:
14090 DUK_DDD(DUK_DDDPRINT("done; src=%p, src_end=%p, n_chars=%ld",
14091 (const void *) src, (const void *) src_end, (long) n_chars));
14092
14093 DUK_ASSERT(src == src_end);
14094
14095 if (n_chars != 0) {
14096 /* Here we'd have the option of decoding unpadded base64
14097 * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not
14098 * accepted.
14099 */
14100 goto error;
14101 }
14102
14103 *out_dst_final = dst;
14104 return 1;
14105
14106 error:
14107 return 0;
14108}
14109#else /* DUK_USE_BASE64_FASTPATH */
14110DUK_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) {
14111 duk_uint_t t;
14112 duk_uint_fast8_t x, y;
14113 duk_small_uint_t group_idx;
14114 duk_small_uint_t n_equal;
14115 const duk_uint8_t *src_end;
14116
14117 src_end = src + srclen;
14118 t = 0;
14119 group_idx = 0;
14120 n_equal = 0;
14121
14122 while (src < src_end) {
14123 x = *src++;
14124
14125 if (x >= 'A' && x <= 'Z') {
14126 y = x - 'A' + 0;
14127 } else if (x >= 'a' && x <= 'z') {
14128 y = x - 'a' + 26;
14129 } else if (x >= '0' && x <= '9') {
14130 y = x - '0' + 52;
14131 } else if (x == '+') {
14132 y = 62;
14133 } else if (x == '/') {
14134 y = 63;
14135 } else if (x == '=') {
14136 /* We don't check the zero padding bytes here right now
14137 * (that they're actually zero). This seems to be common
14138 * behavior for base-64 decoders.
14139 */
14140
14141 n_equal++;
14142 t <<= 6; /* shift in zeroes */
14143 goto skip_add;
14144 } else if (x == 0x09 || x == 0x0a || x == 0x0d || x == 0x20) {
14145 /* allow basic ASCII whitespace */
14146 continue;
14147 } else {
14148 goto error;
14149 }
14150
14151 if (n_equal > 0) {
14152 /* Don't allow mixed padding and actual chars. */
14153 goto error;
14154 }
14155 t = (t << 6) + y;
14156 skip_add:
14157
14158 if (group_idx == 3) {
14159 /* output 3 bytes from 't' */
14160 *dst++ = (duk_uint8_t) ((t >> 16) & 0xff);
14161 *dst++ = (duk_uint8_t) ((t >> 8) & 0xff);
14162 *dst++ = (duk_uint8_t) (t & 0xff);
14163
14164 if (DUK_UNLIKELY(n_equal > 0)) {
14165 /* Backtrack. */
14166 DUK_ASSERT(n_equal <= 4);
14167 if (n_equal == 1) {
14168 dst -= 1;
14169 } else if (n_equal == 2) {
14170 dst -= 2;
14171 } else {
14172 goto error; /* invalid padding */
14173 }
14174
14175 /* Here we can choose either to end parsing and ignore
14176 * whatever follows, or to continue parsing in case
14177 * multiple (possibly padded) base64 strings have been
14178 * concatenated. Currently, keep on parsing.
14179 */
14180 n_equal = 0;
14181 }
14182
14183 t = 0;
14184 group_idx = 0;
14185 } else {
14186 group_idx++;
14187 }
14188 }
14189
14190 if (group_idx != 0) {
14191 /* Here we'd have the option of decoding unpadded base64
14192 * (e.g. "xxxxyy" instead of "xxxxyy==". Currently not
14193 * accepted.
14194 */
14195 goto error;
14196 }
14197
14198 *out_dst_final = dst;
14199 return 1;
14200
14201 error:
14202 return 0;
14203}
14204#endif /* DUK_USE_BASE64_FASTPATH */
14205
14206DUK_EXTERNAL const char *duk_base64_encode(duk_context *ctx, duk_idx_t idx) {
14207 duk_hthread *thr = (duk_hthread *) ctx;
14208 const duk_uint8_t *src;
14209 duk_size_t srclen;
14210 duk_size_t dstlen;
14211 duk_uint8_t *dst;
14212 const char *ret;
14213
14214 DUK_ASSERT_CTX_VALID(ctx);
14215
14216 /* XXX: optimize for string inputs: no need to coerce to a buffer
14217 * which makes a copy of the input.
14218 */
14219
14220 idx = duk_require_normalize_index(ctx, idx);
14221 src = duk__prep_codec_arg(ctx, idx, &srclen);
14222 /* Note: for srclen=0, src may be NULL */
14223
14224 /* Computation must not wrap; this limit works for 32-bit size_t:
14225 * >>> srclen = 3221225469
14226 * >>> '%x' % ((srclen + 2) / 3 * 4)
14227 * 'fffffffc'
14228 */
14229 if (srclen > 3221225469UL) {
14230 goto type_error;
14231 }
14232 dstlen = (srclen + 2) / 3 * 4;
14233 dst = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, dstlen);
14234
14235 duk__base64_encode_helper((const duk_uint8_t *) src, srclen, dst);
14236
14237 ret = duk_buffer_to_string(ctx, -1); /* Safe, result is ASCII. */
14238 duk_replace(ctx, idx);
14239 return ret;
14240
14241 type_error:
14242 DUK_ERROR_TYPE(thr, DUK_STR_ENCODE_FAILED);
14243 return NULL; /* never here */
14244}
14245
14246DUK_EXTERNAL void duk_base64_decode(duk_context *ctx, duk_idx_t idx) {
14247 duk_hthread *thr = (duk_hthread *) ctx;
14248 const duk_uint8_t *src;
14249 duk_size_t srclen;
14250 duk_size_t dstlen;
14251 duk_uint8_t *dst;
14252 duk_uint8_t *dst_final;
14253 duk_bool_t retval;
14254
14255 DUK_ASSERT_CTX_VALID(ctx);
14256
14257 /* XXX: optimize for buffer inputs: no need to coerce to a string
14258 * which causes an unnecessary interning.
14259 */
14260
14261 idx = duk_require_normalize_index(ctx, idx);
14262 src = duk__prep_codec_arg(ctx, idx, &srclen);
14263
14264 /* Computation must not wrap, only srclen + 3 is at risk of
14265 * wrapping because after that the number gets smaller.
14266 * This limit works for 32-bit size_t:
14267 * 0x100000000 - 3 - 1 = 4294967292
14268 */
14269 if (srclen > 4294967292UL) {
14270 goto type_error;
14271 }
14272 dstlen = (srclen + 3) / 4 * 3; /* upper limit, assuming no whitespace etc */
14273 dst = (duk_uint8_t *) duk_push_dynamic_buffer(ctx, dstlen);
14274 /* Note: for dstlen=0, dst may be NULL */
14275
14276 retval = duk__base64_decode_helper((const duk_uint8_t *) src, srclen, dst, &dst_final);
14277 if (!retval) {
14278 goto type_error;
14279 }
14280
14281 /* XXX: convert to fixed buffer? */
14282 (void) duk_resize_buffer(ctx, -1, (duk_size_t) (dst_final - dst));
14283 duk_replace(ctx, idx);
14284 return;
14285
14286 type_error:
14287 DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED);
14288}
14289
14290DUK_EXTERNAL const char *duk_hex_encode(duk_context *ctx, duk_idx_t idx) {
14291 const duk_uint8_t *inp;
14292 duk_size_t len;
14293 duk_size_t i;
14294 duk_uint8_t *buf;
14295 const char *ret;
14296#if defined(DUK_USE_HEX_FASTPATH)
14297 duk_size_t len_safe;
14298 duk_uint16_t *p16;
14299#endif
14300
14301 DUK_ASSERT_CTX_VALID(ctx);
14302
14303 idx = duk_require_normalize_index(ctx, idx);
14304 inp = duk__prep_codec_arg(ctx, idx, &len);
14305 DUK_ASSERT(inp != NULL || len == 0);
14306
14307 /* Fixed buffer, no zeroing because we'll fill all the data. */
14308 buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, len * 2);
14309 DUK_ASSERT(buf != NULL);
14310
14311#if defined(DUK_USE_HEX_FASTPATH)
14312 DUK_ASSERT((((duk_size_t) buf) & 0x01U) == 0); /* pointer is aligned, guaranteed for fixed buffer */
14313 p16 = (duk_uint16_t *) (void *) buf;
14314 len_safe = len & ~0x03U;
14315 for (i = 0; i < len_safe; i += 4) {
14316 p16[0] = duk_hex_enctab[inp[i]];
14317 p16[1] = duk_hex_enctab[inp[i + 1]];
14318 p16[2] = duk_hex_enctab[inp[i + 2]];
14319 p16[3] = duk_hex_enctab[inp[i + 3]];
14320 p16 += 4;
14321 }
14322 for (; i < len; i++) {
14323 *p16++ = duk_hex_enctab[inp[i]];
14324 }
14325#else /* DUK_USE_HEX_FASTPATH */
14326 for (i = 0; i < len; i++) {
14327 duk_small_uint_t t;
14328 t = (duk_small_uint_t) inp[i];
14329 buf[i*2 + 0] = duk_lc_digits[t >> 4];
14330 buf[i*2 + 1] = duk_lc_digits[t & 0x0f];
14331 }
14332#endif /* DUK_USE_HEX_FASTPATH */
14333
14334 /* XXX: Using a string return value forces a string intern which is
14335 * not always necessary. As a rough performance measure, hex encode
14336 * time for tests/perf/test-hex-encode.js dropped from ~35s to ~15s
14337 * without string coercion. Change to returning a buffer and let the
14338 * caller coerce to string if necessary?
14339 */
14340
14341 ret = duk_buffer_to_string(ctx, -1); /* Safe, result is ASCII. */
14342 duk_replace(ctx, idx);
14343 return ret;
14344}
14345
14346DUK_EXTERNAL void duk_hex_decode(duk_context *ctx, duk_idx_t idx) {
14347 duk_hthread *thr = (duk_hthread *) ctx;
14348 const duk_uint8_t *inp;
14349 duk_size_t len;
14350 duk_size_t i;
14351 duk_int_t t;
14352 duk_uint8_t *buf;
14353#if defined(DUK_USE_HEX_FASTPATH)
14354 duk_int_t chk;
14355 duk_uint8_t *p;
14356 duk_size_t len_safe;
14357#endif
14358
14359 DUK_ASSERT_CTX_VALID(ctx);
14360
14361 idx = duk_require_normalize_index(ctx, idx);
14362 inp = duk__prep_codec_arg(ctx, idx, &len);
14363 DUK_ASSERT(inp != NULL || len == 0);
14364
14365 if (len & 0x01) {
14366 goto type_error;
14367 }
14368
14369 /* Fixed buffer, no zeroing because we'll fill all the data. */
14370 buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, len / 2);
14371 DUK_ASSERT(buf != NULL);
14372
14373#if defined(DUK_USE_HEX_FASTPATH)
14374 p = buf;
14375 len_safe = len & ~0x07U;
14376 for (i = 0; i < len_safe; i += 8) {
14377 t = ((duk_int_t) duk_hex_dectab_shift4[inp[i]]) |
14378 ((duk_int_t) duk_hex_dectab[inp[i + 1]]);
14379 chk = t;
14380 p[0] = (duk_uint8_t) t;
14381 t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 2]]) |
14382 ((duk_int_t) duk_hex_dectab[inp[i + 3]]);
14383 chk |= t;
14384 p[1] = (duk_uint8_t) t;
14385 t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 4]]) |
14386 ((duk_int_t) duk_hex_dectab[inp[i + 5]]);
14387 chk |= t;
14388 p[2] = (duk_uint8_t) t;
14389 t = ((duk_int_t) duk_hex_dectab_shift4[inp[i + 6]]) |
14390 ((duk_int_t) duk_hex_dectab[inp[i + 7]]);
14391 chk |= t;
14392 p[3] = (duk_uint8_t) t;
14393 p += 4;
14394
14395 /* Check if any lookup above had a negative result. */
14396 if (DUK_UNLIKELY(chk < 0)) {
14397 goto type_error;
14398 }
14399 }
14400 for (; i < len; i += 2) {
14401 t = (((duk_int_t) duk_hex_dectab[inp[i]]) << 4) |
14402 ((duk_int_t) duk_hex_dectab[inp[i + 1]]);
14403 if (DUK_UNLIKELY(t < 0)) {
14404 goto type_error;
14405 }
14406 *p++ = (duk_uint8_t) t;
14407 }
14408#else /* DUK_USE_HEX_FASTPATH */
14409 for (i = 0; i < len; i += 2) {
14410 /* For invalid characters the value -1 gets extended to
14411 * at least 16 bits. If either nybble is invalid, the
14412 * resulting 't' will be < 0.
14413 */
14414 t = (((duk_int_t) duk_hex_dectab[inp[i]]) << 4) |
14415 ((duk_int_t) duk_hex_dectab[inp[i + 1]]);
14416 if (DUK_UNLIKELY(t < 0)) {
14417 goto type_error;
14418 }
14419 buf[i >> 1] = (duk_uint8_t) t;
14420 }
14421#endif /* DUK_USE_HEX_FASTPATH */
14422
14423 duk_replace(ctx, idx);
14424 return;
14425
14426 type_error:
14427 DUK_ERROR_TYPE(thr, DUK_STR_DECODE_FAILED);
14428}
14429
14430#if defined(DUK_USE_JSON_SUPPORT)
14431DUK_EXTERNAL const char *duk_json_encode(duk_context *ctx, duk_idx_t idx) {
14432#if defined(DUK_USE_ASSERTIONS)
14433 duk_idx_t top_at_entry;
14434#endif
14435 const char *ret;
14436
14437 DUK_ASSERT_CTX_VALID(ctx);
14438#if defined(DUK_USE_ASSERTIONS)
14439 top_at_entry = duk_get_top(ctx);
14440#endif
14441
14442 idx = duk_require_normalize_index(ctx, idx);
14443 duk_bi_json_stringify_helper(ctx,
14444 idx /*idx_value*/,
14445 DUK_INVALID_INDEX /*idx_replacer*/,
14446 DUK_INVALID_INDEX /*idx_space*/,
14447 0 /*flags*/);
14448 DUK_ASSERT(duk_is_string(ctx, -1));
14449 duk_replace(ctx, idx);
14450 ret = duk_get_string(ctx, idx);
14451
14452 DUK_ASSERT(duk_get_top(ctx) == top_at_entry);
14453
14454 return ret;
14455}
14456
14457DUK_EXTERNAL void duk_json_decode(duk_context *ctx, duk_idx_t idx) {
14458#if defined(DUK_USE_ASSERTIONS)
14459 duk_idx_t top_at_entry;
14460#endif
14461
14462 DUK_ASSERT_CTX_VALID(ctx);
14463#if defined(DUK_USE_ASSERTIONS)
14464 top_at_entry = duk_get_top(ctx);
14465#endif
14466
14467 idx = duk_require_normalize_index(ctx, idx);
14468 duk_bi_json_parse_helper(ctx,
14469 idx /*idx_value*/,
14470 DUK_INVALID_INDEX /*idx_reviver*/,
14471 0 /*flags*/);
14472 duk_replace(ctx, idx);
14473
14474 DUK_ASSERT(duk_get_top(ctx) == top_at_entry);
14475}
14476#else /* DUK_USE_JSON_SUPPORT */
14477DUK_EXTERNAL const char *duk_json_encode(duk_context *ctx, duk_idx_t idx) {
14478 DUK_UNREF(idx);
14479 DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx);
14480}
14481
14482DUK_EXTERNAL void duk_json_decode(duk_context *ctx, duk_idx_t idx) {
14483 DUK_UNREF(idx);
14484 DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx);
14485}
14486#endif /* DUK_USE_JSON_SUPPORT */
14487/*
14488 * Compilation and evaluation
14489 */
14490
14491/* #include duk_internal.h -> already included */
14492
14494struct duk__compile_raw_args {
14495 duk_size_t src_length; /* should be first on 64-bit platforms */
14496 const duk_uint8_t *src_buffer;
14497 duk_uint_t flags;
14498};
14499
14500/* Eval is just a wrapper now. */
14501DUK_EXTERNAL duk_int_t duk_eval_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
14502 duk_uint_t comp_flags;
14503 duk_int_t rc;
14504
14505 DUK_ASSERT_CTX_VALID(ctx);
14506
14507 /* Note: strictness is *not* inherited from the current Duktape/C.
14508 * This would be confusing because the current strictness state
14509 * depends on whether we're running inside a Duktape/C activation
14510 * (= strict mode) or outside of any activation (= non-strict mode).
14511 * See tests/api/test-eval-strictness.c for more discussion.
14512 */
14513
14514 /* [ ... source? filename? ] (depends on flags) */
14515
14516 comp_flags = flags;
14517 comp_flags |= DUK_COMPILE_EVAL;
14518 rc = duk_compile_raw(ctx, src_buffer, src_length, comp_flags); /* may be safe, or non-safe depending on flags */
14519
14520 /* [ ... closure/error ] */
14521
14522 if (rc != DUK_EXEC_SUCCESS) {
14523 rc = DUK_EXEC_ERROR;
14524 goto got_rc;
14525 }
14526
14527 duk_push_global_object(ctx); /* explicit 'this' binding, see GH-164 */
14528
14529 if (flags & DUK_COMPILE_SAFE) {
14530 rc = duk_pcall_method(ctx, 0);
14531 } else {
14532 duk_call_method(ctx, 0);
14533 rc = DUK_EXEC_SUCCESS;
14534 }
14535
14536 /* [ ... result/error ] */
14537
14538 got_rc:
14539 if (flags & DUK_COMPILE_NORESULT) {
14540 duk_pop(ctx);
14541 }
14542
14543 return rc;
14544}
14545
14546/* Helper which can be called both directly and with duk_safe_call(). */
14547DUK_LOCAL duk_ret_t duk__do_compile(duk_context *ctx, void *udata) {
14548 duk_hthread *thr = (duk_hthread *) ctx;
14549 duk__compile_raw_args *comp_args;
14550 duk_uint_t flags;
14551 duk_small_uint_t comp_flags;
14552 duk_hcompfunc *h_templ;
14553
14554 DUK_ASSERT_CTX_VALID(ctx);
14555 DUK_ASSERT(udata != NULL);
14556
14557 /* Note: strictness is not inherited from the current Duktape/C
14558 * context. Otherwise it would not be possible to compile
14559 * non-strict code inside a Duktape/C activation (which is
14560 * always strict now). See tests/api/test-eval-strictness.c
14561 * for discussion.
14562 */
14563
14564 /* [ ... source? filename? ] (depends on flags) */
14565
14566 comp_args = (duk__compile_raw_args *) udata;
14567 flags = comp_args->flags;
14568
14569 if (flags & DUK_COMPILE_NOFILENAME) {
14570 /* Automatic filename: 'eval' or 'input'. */
14571 duk_push_hstring_stridx(ctx, (flags & DUK_COMPILE_EVAL) ? DUK_STRIDX_EVAL : DUK_STRIDX_INPUT);
14572 }
14573
14574 /* [ ... source? filename ] */
14575
14576 if (!comp_args->src_buffer) {
14577 duk_hstring *h_sourcecode;
14578
14579 h_sourcecode = duk_get_hstring(ctx, -2);
14580 if ((flags & DUK_COMPILE_NOSOURCE) || /* args incorrect */
14581 (h_sourcecode == NULL)) { /* e.g. duk_push_string_file_raw() pushed undefined */
14582 DUK_ERROR_TYPE(thr, DUK_STR_NO_SOURCECODE);
14583 }
14584 DUK_ASSERT(h_sourcecode != NULL);
14585 comp_args->src_buffer = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode);
14586 comp_args->src_length = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode);
14587 }
14588 DUK_ASSERT(comp_args->src_buffer != NULL);
14589
14590 /* XXX: unnecessary translation of flags */
14591 comp_flags = 0;
14592 if (flags & DUK_COMPILE_EVAL) {
14593 comp_flags |= DUK_JS_COMPILE_FLAG_EVAL;
14594 }
14595 if (flags & DUK_COMPILE_FUNCTION) {
14596 comp_flags |= DUK_JS_COMPILE_FLAG_EVAL |
14597 DUK_JS_COMPILE_FLAG_FUNCEXPR;
14598 }
14599 if (flags & DUK_COMPILE_STRICT) {
14600 comp_flags |= DUK_JS_COMPILE_FLAG_STRICT;
14601 }
14602
14603 /* [ ... source? filename ] */
14604
14605 duk_js_compile(thr, comp_args->src_buffer, comp_args->src_length, comp_flags);
14606
14607 /* [ ... source? func_template ] */
14608
14609 if (flags & DUK_COMPILE_NOSOURCE) {
14610 ;
14611 } else {
14612 duk_remove_m2(ctx);
14613 }
14614
14615 /* [ ... func_template ] */
14616
14617 h_templ = (duk_hcompfunc *) duk_known_hobject(ctx, -1);
14618 duk_js_push_closure(thr,
14619 h_templ,
14620 thr->builtins[DUK_BIDX_GLOBAL_ENV],
14621 thr->builtins[DUK_BIDX_GLOBAL_ENV],
14622 1 /*add_auto_proto*/);
14623 duk_remove_m2(ctx); /* -> [ ... closure ] */
14624
14625 /* [ ... closure ] */
14626
14627 return 1;
14628}
14629
14630DUK_EXTERNAL duk_int_t duk_compile_raw(duk_context *ctx, const char *src_buffer, duk_size_t src_length, duk_uint_t flags) {
14631 duk__compile_raw_args comp_args_alloc;
14632 duk__compile_raw_args *comp_args = &comp_args_alloc;
14633
14634 DUK_ASSERT_CTX_VALID(ctx);
14635
14636 if ((flags & DUK_COMPILE_STRLEN) && (src_buffer != NULL)) {
14637 /* String length is computed here to avoid multiple evaluation
14638 * of a macro argument in the calling side.
14639 */
14640 src_length = DUK_STRLEN(src_buffer);
14641 }
14642
14643 comp_args->src_buffer = (const duk_uint8_t *) src_buffer;
14644 comp_args->src_length = src_length;
14645 comp_args->flags = flags;
14646
14647 /* [ ... source? filename? ] (depends on flags) */
14648
14649 if (flags & DUK_COMPILE_SAFE) {
14650 duk_int_t rc;
14651 duk_int_t nargs;
14652 duk_int_t nrets = 1;
14653
14654 /* Arguments can be: [ source? filename? &comp_args] so that
14655 * nargs is 1 to 3. Call site encodes the correct nargs count
14656 * directly into flags.
14657 */
14658 nargs = flags & 0x07;
14659 DUK_ASSERT(nargs == ((flags & DUK_COMPILE_NOSOURCE) ? 0 : 1) +
14660 ((flags & DUK_COMPILE_NOFILENAME) ? 0 : 1));
14661 rc = duk_safe_call(ctx, duk__do_compile, (void *) comp_args, nargs, nrets);
14662
14663 /* [ ... closure ] */
14664 return rc;
14665 }
14666
14667 (void) duk__do_compile(ctx, (void *) comp_args);
14668
14669 /* [ ... closure ] */
14670 return DUK_EXEC_SUCCESS;
14671}
14672/*
14673 * Debugging related API calls
14674 */
14675
14676/* #include duk_internal.h -> already included */
14677
14678#if defined(DUK_USE_JSON_SUPPORT)
14679DUK_EXTERNAL void duk_push_context_dump(duk_context *ctx) {
14680 duk_idx_t idx;
14681 duk_idx_t top;
14682
14683 DUK_ASSERT_CTX_VALID(ctx);
14684
14685 /* We don't duk_require_stack() here now, but rely on the caller having
14686 * enough space.
14687 */
14688
14689 top = duk_get_top(ctx);
14690 duk_push_array(ctx);
14691 for (idx = 0; idx < top; idx++) {
14692 duk_dup(ctx, idx);
14693 duk_put_prop_index(ctx, -2, idx);
14694 }
14695
14696 /* XXX: conversion errors should not propagate outwards.
14697 * Perhaps values need to be coerced individually?
14698 */
14699 duk_bi_json_stringify_helper(ctx,
14700 duk_get_top_index(ctx), /*idx_value*/
14701 DUK_INVALID_INDEX, /*idx_replacer*/
14702 DUK_INVALID_INDEX, /*idx_space*/
14703 DUK_JSON_FLAG_EXT_CUSTOM |
14704 DUK_JSON_FLAG_ASCII_ONLY |
14705 DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/);
14706
14707 duk_push_sprintf(ctx, "ctx: top=%ld, stack=%s", (long) top, (const char *) duk_safe_to_string(ctx, -1));
14708 duk_replace(ctx, -3); /* [ ... arr jsonx(arr) res ] -> [ ... res jsonx(arr) ] */
14709 duk_pop(ctx);
14710 DUK_ASSERT(duk_is_string(ctx, -1));
14711}
14712#else /* DUK_USE_JSON_SUPPORT */
14713DUK_EXTERNAL void duk_push_context_dump(duk_context *ctx) {
14714 DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx);
14715}
14716#endif /* DUK_USE_JSON_SUPPORT */
14717
14718#if defined(DUK_USE_DEBUGGER_SUPPORT)
14719
14720DUK_EXTERNAL void duk_debugger_attach(duk_context *ctx,
14721 duk_debug_read_function read_cb,
14722 duk_debug_write_function write_cb,
14723 duk_debug_peek_function peek_cb,
14724 duk_debug_read_flush_function read_flush_cb,
14725 duk_debug_write_flush_function write_flush_cb,
14726 duk_debug_request_function request_cb,
14727 duk_debug_detached_function detached_cb,
14728 void *udata) {
14729 duk_hthread *thr = (duk_hthread *) ctx;
14730 duk_heap *heap;
14731 const char *str;
14732 duk_size_t len;
14733
14734 /* XXX: should there be an error or an automatic detach if
14735 * already attached?
14736 */
14737
14738 DUK_D(DUK_DPRINT("application called duk_debugger_attach()"));
14739
14740 DUK_ASSERT_CTX_VALID(ctx);
14741 DUK_ASSERT(read_cb != NULL);
14742 DUK_ASSERT(write_cb != NULL);
14743 /* Other callbacks are optional. */
14744
14745 heap = thr->heap;
14746 heap->dbg_read_cb = read_cb;
14747 heap->dbg_write_cb = write_cb;
14748 heap->dbg_peek_cb = peek_cb;
14749 heap->dbg_read_flush_cb = read_flush_cb;
14750 heap->dbg_write_flush_cb = write_flush_cb;
14751 heap->dbg_request_cb = request_cb;
14752 heap->dbg_detached_cb = detached_cb;
14753 heap->dbg_udata = udata;
14754 heap->dbg_have_next_byte = 0;
14755
14756 /* Start in paused state. */
14757 heap->dbg_processing = 0;
14758 DUK_HEAP_SET_DEBUGGER_PAUSED(heap);
14759 heap->dbg_state_dirty = 1;
14760 heap->dbg_force_restart = 0;
14761 heap->dbg_step_type = 0;
14762 heap->dbg_step_thread = NULL;
14763 heap->dbg_step_csindex = 0;
14764 heap->dbg_step_startline = 0;
14765 heap->dbg_exec_counter = 0;
14766 heap->dbg_last_counter = 0;
14767 heap->dbg_last_time = 0.0;
14768
14769 /* Send version identification and flush right afterwards. Note that
14770 * we must write raw, unframed bytes here.
14771 */
14772 duk_push_sprintf(ctx, "%ld %ld %s %s\n",
14773 (long) DUK_DEBUG_PROTOCOL_VERSION,
14774 (long) DUK_VERSION,
14775 (const char *) DUK_GIT_DESCRIBE,
14776 (const char *) DUK_USE_TARGET_INFO);
14777 str = duk_get_lstring(ctx, -1, &len);
14778 DUK_ASSERT(str != NULL);
14779 duk_debug_write_bytes(thr, (const duk_uint8_t *) str, len);
14780 duk_debug_write_flush(thr);
14781 duk_pop(ctx);
14782}
14783
14784DUK_EXTERNAL void duk_debugger_detach(duk_context *ctx) {
14785 duk_hthread *thr;
14786
14787 DUK_D(DUK_DPRINT("application called duk_debugger_detach()"));
14788
14789 DUK_ASSERT_CTX_VALID(ctx);
14790 thr = (duk_hthread *) ctx;
14791 DUK_ASSERT(thr != NULL);
14792 DUK_ASSERT(thr->heap != NULL);
14793
14794 /* Can be called multiple times with no harm. */
14795 duk_debug_do_detach(thr->heap);
14796}
14797
14798DUK_EXTERNAL void duk_debugger_cooperate(duk_context *ctx) {
14799 duk_hthread *thr;
14800 duk_bool_t processed_messages;
14801
14802 DUK_ASSERT_CTX_VALID(ctx);
14803 thr = (duk_hthread *) ctx;
14804 DUK_ASSERT(thr != NULL);
14805 DUK_ASSERT(thr->heap != NULL);
14806
14807 if (!DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
14808 return;
14809 }
14810 if (thr->callstack_top > 0 || thr->heap->dbg_processing) {
14811 /* Calling duk_debugger_cooperate() while Duktape is being
14812 * called into is not supported. This is not a 100% check
14813 * but prevents any damage in most cases.
14814 */
14815 return;
14816 }
14817
14818 processed_messages = duk_debug_process_messages(thr, 1 /*no_block*/);
14819 DUK_UNREF(processed_messages);
14820}
14821
14822DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_context *ctx, duk_idx_t nvalues) {
14823 duk_hthread *thr;
14824 duk_idx_t top;
14825 duk_idx_t idx;
14826 duk_bool_t ret = 0;
14827
14828 DUK_ASSERT_CTX_VALID(ctx);
14829 thr = (duk_hthread *) ctx;
14830 DUK_ASSERT(thr != NULL);
14831 DUK_ASSERT(thr->heap != NULL);
14832
14833 DUK_D(DUK_DPRINT("application called duk_debugger_notify() with nvalues=%ld", (long) nvalues));
14834
14835 top = duk_get_top(ctx);
14836 if (top < nvalues) {
14837 DUK_ERROR_RANGE(thr, "not enough stack values for notify");
14838 return ret; /* unreachable */
14839 }
14840 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
14841 duk_debug_write_notify(thr, DUK_DBG_CMD_APPNOTIFY);
14842 for (idx = top - nvalues; idx < top; idx++) {
14843 duk_tval *tv = DUK_GET_TVAL_POSIDX(ctx, idx);
14844 duk_debug_write_tval(thr, tv);
14845 }
14846 duk_debug_write_eom(thr);
14847
14848 /* Return non-zero (true) if we have a good reason to believe
14849 * the notify was delivered; if we're still attached at least
14850 * a transport error was not indicated by the transport write
14851 * callback. This is not a 100% guarantee of course.
14852 */
14853 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
14854 ret = 1;
14855 }
14856 }
14857 duk_pop_n(ctx, nvalues);
14858 return ret;
14859}
14860
14861DUK_EXTERNAL void duk_debugger_pause(duk_context *ctx) {
14862 duk_hthread *thr;
14863
14864 DUK_ASSERT_CTX_VALID(ctx);
14865 thr = (duk_hthread *) ctx;
14866 DUK_ASSERT(thr != NULL);
14867 DUK_ASSERT(thr->heap != NULL);
14868
14869 DUK_D(DUK_DPRINT("application called duk_debugger_pause()"));
14870
14871 /* Treat like a debugger statement: ignore when not attached. */
14872 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
14873 DUK_HEAP_SET_PAUSED(thr->heap);
14874
14875 /* Pause on the next opcode executed. This is always safe to do even
14876 * inside the debugger message loop: the interrupt counter will be reset
14877 * to its proper value when the message loop exits.
14878 */
14879 thr->interrupt_init = 1;
14880 thr->interrupt_counter = 0;
14881 }
14882}
14883
14884#else /* DUK_USE_DEBUGGER_SUPPORT */
14885
14886DUK_EXTERNAL void duk_debugger_attach(duk_context *ctx,
14887 duk_debug_read_function read_cb,
14888 duk_debug_write_function write_cb,
14889 duk_debug_peek_function peek_cb,
14890 duk_debug_read_flush_function read_flush_cb,
14891 duk_debug_write_flush_function write_flush_cb,
14892 duk_debug_request_function request_cb,
14893 duk_debug_detached_function detached_cb,
14894 void *udata) {
14895 DUK_ASSERT_CTX_VALID(ctx);
14896 DUK_UNREF(read_cb);
14897 DUK_UNREF(write_cb);
14898 DUK_UNREF(peek_cb);
14899 DUK_UNREF(read_flush_cb);
14900 DUK_UNREF(write_flush_cb);
14901 DUK_UNREF(request_cb);
14902 DUK_UNREF(detached_cb);
14903 DUK_UNREF(udata);
14904 DUK_ERROR_TYPE((duk_hthread *) ctx, "no debugger support");
14905}
14906
14907DUK_EXTERNAL void duk_debugger_detach(duk_context *ctx) {
14908 DUK_ASSERT_CTX_VALID(ctx);
14909 DUK_ERROR_TYPE((duk_hthread *) ctx, "no debugger support");
14910}
14911
14912DUK_EXTERNAL void duk_debugger_cooperate(duk_context *ctx) {
14913 /* nop */
14914 DUK_ASSERT_CTX_VALID(ctx);
14915 DUK_UNREF(ctx);
14916}
14917
14918DUK_EXTERNAL duk_bool_t duk_debugger_notify(duk_context *ctx, duk_idx_t nvalues) {
14919 duk_idx_t top;
14920
14921 DUK_ASSERT_CTX_VALID(ctx);
14922
14923 top = duk_get_top(ctx);
14924 if (top < nvalues) {
14925 DUK_ERROR_RANGE_INVALID_COUNT((duk_hthread *) ctx);
14926 return 0; /* unreachable */
14927 }
14928
14929 /* No debugger support, just pop values. */
14930 duk_pop_n(ctx, nvalues);
14931 return 0;
14933
14934DUK_EXTERNAL void duk_debugger_pause(duk_context *ctx) {
14935 /* Treat like debugger statement: nop */
14936 DUK_ASSERT_CTX_VALID(ctx);
14937 DUK_UNREF(ctx);
14938}
14939
14940#endif /* DUK_USE_DEBUGGER_SUPPORT */
14941/*
14942 * Heap creation and destruction
14943 */
14944
14945/* #include duk_internal.h -> already included */
14946
14948
14950 duk_ljstate lj;
14951 duk_bool_t handling_error;
14952 duk_hthread *curr_thread;
14953 duk_int_t call_recursion_depth;
14954};
14955
14956DUK_EXTERNAL
14957duk_context *duk_create_heap(duk_alloc_function alloc_func,
14958 duk_realloc_function realloc_func,
14959 duk_free_function free_func,
14960 void *heap_udata,
14961 duk_fatal_function fatal_handler) {
14962 duk_heap *heap = NULL;
14963 duk_context *ctx;
14964
14965 /* Assume that either all memory funcs are NULL or non-NULL, mixed
14966 * cases will now be unsafe.
14967 */
14968
14969 /* XXX: just assert non-NULL values here and make caller arguments
14970 * do the defaulting to the default implementations (smaller code)?
14971 */
14972
14973 if (!alloc_func) {
14974 DUK_ASSERT(realloc_func == NULL);
14975 DUK_ASSERT(free_func == NULL);
14976#if defined(DUK_USE_PROVIDE_DEFAULT_ALLOC_FUNCTIONS)
14977 alloc_func = duk_default_alloc_function;
14978 realloc_func = duk_default_realloc_function;
14979 free_func = duk_default_free_function;
14980#else
14981 DUK_D(DUK_DPRINT("no allocation functions given and no default providers"));
14982 return NULL;
14983#endif
14984 } else {
14985 DUK_ASSERT(realloc_func != NULL);
14986 DUK_ASSERT(free_func != NULL);
14987 }
14988
14989 if (!fatal_handler) {
14990 fatal_handler = duk_default_fatal_handler;
14991 }
14992
14993 DUK_ASSERT(alloc_func != NULL);
14994 DUK_ASSERT(realloc_func != NULL);
14995 DUK_ASSERT(free_func != NULL);
14996 DUK_ASSERT(fatal_handler != NULL);
14997
14998 heap = duk_heap_alloc(alloc_func, realloc_func, free_func, heap_udata, fatal_handler);
14999 if (!heap) {
15000 return NULL;
15001 }
15002 ctx = (duk_context *) heap->heap_thread;
15003 DUK_ASSERT(ctx != NULL);
15004 DUK_ASSERT(((duk_hthread *) ctx)->heap != NULL);
15005 return ctx;
15006}
15007
15008DUK_EXTERNAL void duk_destroy_heap(duk_context *ctx) {
15009 duk_hthread *thr = (duk_hthread *) ctx;
15010 duk_heap *heap;
15011
15012 if (!ctx) {
15013 return;
15014 }
15015 heap = thr->heap;
15016 DUK_ASSERT(heap != NULL);
15017
15018 duk_heap_free(heap);
15019}
15020
15021DUK_EXTERNAL void duk_suspend(duk_context *ctx, duk_thread_state *state) {
15022 duk_hthread *thr = (duk_hthread *) ctx;
15023 duk_internal_thread_state *snapshot = (duk_internal_thread_state *) (void *) state;
15024 duk_heap *heap;
15025 duk_ljstate *lj;
15026
15027 DUK_ASSERT_CTX_VALID(ctx);
15028 DUK_ASSERT(thr != NULL);
15029 DUK_ASSERT(thr->heap != NULL);
15030 DUK_ASSERT(state != NULL); /* unvalidated */
15031
15032 heap = thr->heap;
15033 lj = &heap->lj;
15034
15035 duk_push_tval(ctx, &lj->value1);
15036 duk_push_tval(ctx, &lj->value2);
15037
15038 DUK_MEMCPY((void *) &snapshot->lj, (const void *) lj, sizeof(duk_ljstate));
15039 snapshot->handling_error = heap->handling_error;
15040 snapshot->curr_thread = heap->curr_thread;
15041 snapshot->call_recursion_depth = heap->call_recursion_depth;
15042
15043 lj->jmpbuf_ptr = NULL;
15044 lj->type = DUK_LJ_TYPE_UNKNOWN;
15045 DUK_TVAL_SET_UNDEFINED(&lj->value1);
15046 DUK_TVAL_SET_UNDEFINED(&lj->value2);
15047 heap->handling_error = 0;
15048 heap->curr_thread = NULL;
15049 heap->call_recursion_depth = 0;
15050}
15051
15052DUK_EXTERNAL void duk_resume(duk_context *ctx, const duk_thread_state *state) {
15053 duk_hthread *thr = (duk_hthread *) ctx;
15054 const duk_internal_thread_state *snapshot = (const duk_internal_thread_state *) (const void *) state;
15055 duk_heap *heap;
15056
15057 DUK_ASSERT_CTX_VALID(ctx);
15058 DUK_ASSERT(thr != NULL);
15059 DUK_ASSERT(thr->heap != NULL);
15060 DUK_ASSERT(state != NULL); /* unvalidated */
15061
15062 heap = thr->heap;
15063
15064 DUK_MEMCPY((void *) &heap->lj, (const void *) &snapshot->lj, sizeof(duk_ljstate));
15065 heap->handling_error = snapshot->handling_error;
15066 heap->curr_thread = snapshot->curr_thread;
15067 heap->call_recursion_depth = snapshot->call_recursion_depth;
15068
15069 duk_pop_2(ctx);
15070}
15071
15072/* XXX: better place for this */
15073DUK_EXTERNAL void duk_set_global_object(duk_context *ctx) {
15074 duk_hthread *thr = (duk_hthread *) ctx;
15075 duk_hobject *h_glob;
15076 duk_hobject *h_prev_glob;
15077 duk_hobject *h_env;
15078 duk_hobject *h_prev_env;
15079
15080 DUK_D(DUK_DPRINT("replace global object with: %!T", duk_get_tval(ctx, -1)));
15081
15082 h_glob = duk_require_hobject(ctx, -1);
15083 DUK_ASSERT(h_glob != NULL);
15084
15085 /*
15086 * Replace global object.
15087 */
15088
15089 h_prev_glob = thr->builtins[DUK_BIDX_GLOBAL];
15090 DUK_UNREF(h_prev_glob);
15091 thr->builtins[DUK_BIDX_GLOBAL] = h_glob;
15092 DUK_HOBJECT_INCREF(thr, h_glob);
15093 DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_prev_glob); /* side effects, in theory (referenced by global env) */
15094
15095 /*
15096 * Replace lexical environment for global scope
15097 *
15098 * Create a new object environment for the global lexical scope.
15099 * We can't just reset the _Target property of the current one,
15100 * because the lexical scope is shared by other threads with the
15101 * same (initial) built-ins.
15102 */
15103
15104 h_env = duk_push_object_helper(ctx,
15105 DUK_HOBJECT_FLAG_EXTENSIBLE |
15106 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV),
15107 -1); /* no prototype, updated below */
15108 DUK_ASSERT(h_env != NULL);
15109
15110 duk_dup_m2(ctx);
15111 duk_dup_m3(ctx);
15112 duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
15113 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE);
15114
15115 /* [ ... new_glob new_env ] */
15116
15117 h_prev_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
15118 thr->builtins[DUK_BIDX_GLOBAL_ENV] = h_env;
15119 DUK_HOBJECT_INCREF(thr, h_env);
15120 DUK_HOBJECT_DECREF_ALLOWNULL(thr, h_prev_env); /* side effects */
15121 DUK_UNREF(h_env); /* without refcounts */
15122 DUK_UNREF(h_prev_env);
15123
15124 /* [ ... new_glob new_env ] */
15125
15126 duk_pop_2(ctx);
15127
15128 /* [ ... ] */
15129}
15130/*
15131 * Inspection
15132 */
15133
15134/* #include duk_internal.h -> already included */
15135
15136/* For footprint efficient multiple value setting: arrays are much better than
15137 * varargs, format string with parsing is often better than string pointer arrays.
15138 */
15139DUK_LOCAL void duk__inspect_multiple_uint(duk_context *ctx, const char *fmt, duk_int_t *vals) {
15140 duk_int_t val;
15141 const char *p;
15142 const char *p_curr;
15143 duk_size_t len;
15144
15145 for (p = fmt;;) {
15146 len = DUK_STRLEN(p);
15147 p_curr = p;
15148 p += len + 1;
15149 if (len == 0) {
15150 /* Double NUL (= empty key) terminates. */
15151 break;
15152 }
15153 val = *vals++;
15154 if (val >= 0) {
15155 /* Negative values are markers to skip key. */
15156 duk_push_string(ctx, p_curr);
15157 duk_push_uint(ctx, val);
15158 duk_put_prop(ctx, -3);
15159 }
15160 }
15161}
15162
15163/* Raw helper to extract internal information / statistics about a value.
15164 * The return value is an object with properties that are version specific.
15165 * The properties must not expose anything that would lead to security
15166 * issues (e.g. exposing compiled function 'data' buffer might be an issue).
15167 * Currently only counts and sizes and such are given so there shouldn't
15168 * be security implications.
15169 */
15170
15171#define DUK__IDX_TYPE 0
15172#define DUK__IDX_ITAG 1
15173#define DUK__IDX_REFC 2
15174#define DUK__IDX_HBYTES 3
15175#define DUK__IDX_CLASS 4
15176#define DUK__IDX_PBYTES 5
15177#define DUK__IDX_ESIZE 6
15178#define DUK__IDX_ENEXT 7
15179#define DUK__IDX_ASIZE 8
15180#define DUK__IDX_HSIZE 9
15181#define DUK__IDX_BCBYTES 10
15182#define DUK__IDX_DBYTES 11
15183#define DUK__IDX_TSTATE 12
15184#define DUK__IDX_VARIANT 13
15185
15186DUK_EXTERNAL void duk_inspect_value(duk_context *ctx, duk_idx_t idx) {
15187 duk_hthread *thr = (duk_hthread *) ctx;
15188 duk_tval *tv;
15189 duk_heaphdr *h;
15190 /* The temporary values should be in an array rather than individual
15191 * variables which (in practice) ensures that the compiler won't map
15192 * them to registers and emit a lot of unnecessary shuffling code.
15193 */
15194 duk_int_t vals[14];
15195
15196 DUK_UNREF(thr);
15197
15198 tv = duk_get_tval_or_unused(ctx, idx);
15199 h = (DUK_TVAL_IS_HEAP_ALLOCATED(tv) ? DUK_TVAL_GET_HEAPHDR(tv) : NULL);
15200
15201 /* Assume two's complement and set everything to -1. */
15202 DUK_MEMSET((void *) &vals, (int) 0xff, sizeof(vals));
15203 DUK_ASSERT(vals[DUK__IDX_TYPE] == -1); /* spot check one */
15204
15205 duk_push_bare_object(ctx);
15206
15207 vals[DUK__IDX_TYPE] = duk_get_type_tval(tv);
15208 vals[DUK__IDX_ITAG] = (duk_uint_t) DUK_TVAL_GET_TAG(tv);
15209
15210 if (h == NULL) {
15211 goto finish;
15212 }
15213 duk_push_pointer(ctx, (void *) h);
15214 duk_put_prop_string(ctx, -2, "hptr");
15215
15216#if 0
15217 /* Covers a lot of information, e.g. buffer and string variants. */
15218 duk_push_uint(ctx, (duk_uint_t) DUK_HEAPHDR_GET_FLAGS(h));
15219 duk_put_prop_string(ctx, -2, "hflags");
15220#endif
15221
15222#if defined(DUK_USE_REFERENCE_COUNTING)
15223 vals[DUK__IDX_REFC] = (duk_int_t) DUK_HEAPHDR_GET_REFCOUNT(h);
15224#endif
15225 vals[DUK__IDX_VARIANT] = 0;
15226
15227 /* Heaphdr size and additional allocation size, followed by
15228 * type specific stuff (with varying value count).
15229 */
15230 switch ((duk_small_int_t) DUK_HEAPHDR_GET_TYPE(h)) {
15231 case DUK_HTYPE_STRING: {
15232 duk_hstring *h_str = (duk_hstring *) h;
15233 vals[DUK__IDX_HBYTES] = (duk_int_t) (sizeof(duk_hstring) + DUK_HSTRING_GET_BYTELEN(h_str) + 1);
15234#if defined(DUK_USE_HSTRING_EXTDATA)
15235 if (DUK_HSTRING_HAS_EXTDATA(h_str)) {
15236 vals[DUK__IDX_VARIANT] = 1;
15237 }
15238#endif
15239 break;
15240 }
15241 case DUK_HTYPE_OBJECT: {
15242 duk_hobject *h_obj = (duk_hobject *) h;
15243
15244 /* XXX: variants here are maybe pointless; class is enough? */
15245 if (DUK_HOBJECT_IS_ARRAY(h_obj)) {
15246 vals[DUK__IDX_HBYTES] = sizeof(duk_harray);
15247 } else if (DUK_HOBJECT_IS_COMPFUNC(h_obj)) {
15248 vals[DUK__IDX_HBYTES] = sizeof(duk_hcompfunc);
15249 } else if (DUK_HOBJECT_IS_NATFUNC(h_obj)) {
15250 vals[DUK__IDX_HBYTES] = sizeof(duk_hnatfunc);
15251 } else if (DUK_HOBJECT_IS_THREAD(h_obj)) {
15252 vals[DUK__IDX_HBYTES] = sizeof(duk_hthread);
15253 vals[DUK__IDX_TSTATE] = ((duk_hthread *) h_obj)->state;
15254#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
15255 } else if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
15256 vals[DUK__IDX_HBYTES] = sizeof(duk_hbufobj);
15257 /* XXX: some size information */
15258#endif
15259 } else {
15260 vals[DUK__IDX_HBYTES] = (duk_small_uint_t) sizeof(duk_hobject);
15261 }
15262
15263 vals[DUK__IDX_CLASS] = (duk_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h_obj);
15264 vals[DUK__IDX_PBYTES] = (duk_int_t) DUK_HOBJECT_P_ALLOC_SIZE(h_obj),
15265 vals[DUK__IDX_ESIZE] = (duk_int_t) DUK_HOBJECT_GET_ESIZE(h_obj);
15266 vals[DUK__IDX_ENEXT] = (duk_int_t) DUK_HOBJECT_GET_ENEXT(h_obj);
15267 vals[DUK__IDX_ASIZE] = (duk_int_t) DUK_HOBJECT_GET_ASIZE(h_obj);
15268 vals[DUK__IDX_HSIZE] = (duk_int_t) DUK_HOBJECT_GET_HSIZE(h_obj);
15269
15270 /* Note: e_next indicates the number of gc-reachable entries
15271 * in the entry part, and also indicates the index where the
15272 * next new property would be inserted. It does *not* indicate
15273 * the number of non-NULL keys present in the object. That
15274 * value could be counted separately but requires a pass through
15275 * the key list.
15276 */
15277
15278 if (DUK_HOBJECT_IS_COMPFUNC(h_obj)) {
15279 duk_hbuffer *h_data = (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(thr->heap, (duk_hcompfunc *) h_obj);
15280 vals[DUK__IDX_BCBYTES] = (duk_int_t) (h_data ? DUK_HBUFFER_GET_SIZE(h_data) : 0);
15281 }
15282 break;
15283 }
15284 case DUK_HTYPE_BUFFER: {
15285 duk_hbuffer *h_buf = (duk_hbuffer *) h;
15286
15287 if (DUK_HBUFFER_HAS_DYNAMIC(h_buf)) {
15288 if (DUK_HBUFFER_HAS_EXTERNAL(h_buf)) {
15289 vals[DUK__IDX_VARIANT] = 2; /* buffer variant 2: external */
15290 vals[DUK__IDX_HBYTES] = (duk_uint_t) (sizeof(duk_hbuffer_external));
15291 } else {
15292 /* When alloc_size == 0 the second allocation may not
15293 * actually exist.
15294 */
15295 vals[DUK__IDX_VARIANT] = 1; /* buffer variant 1: dynamic */
15296 vals[DUK__IDX_HBYTES] = (duk_uint_t) (sizeof(duk_hbuffer_dynamic));
15297 }
15298 vals[DUK__IDX_DBYTES] = (duk_uint_t) (DUK_HBUFFER_GET_SIZE(h_buf));
15299 } else {
15300 DUK_ASSERT(vals[DUK__IDX_VARIANT] == 0); /* buffer variant 0: fixed */
15301 vals[DUK__IDX_HBYTES] = (duk_uint_t) (sizeof(duk_hbuffer_fixed) + DUK_HBUFFER_GET_SIZE(h_buf));
15302 }
15303 break;
15304 }
15305 }
15306
15307 finish:
15308 duk__inspect_multiple_uint(ctx,
15309 "type" "\x00" "itag" "\x00" "refc" "\x00" "hbytes" "\x00" "class" "\x00"
15310 "pbytes" "\x00" "esize" "\x00" "enext" "\x00" "asize" "\x00" "hsize" "\x00"
15311 "bcbytes" "\x00" "dbytes" "\x00" "tstate" "\x00" "variant" "\x00" "\x00",
15312 (duk_int_t *) &vals);
15313}
15314
15315DUK_EXTERNAL void duk_inspect_callstack_entry(duk_context *ctx, duk_int_t level) {
15316 duk_hthread *thr = (duk_hthread *) ctx;
15317 duk_activation *act;
15318 duk_uint_fast32_t pc;
15319 duk_uint_fast32_t line;
15320
15321 DUK_ASSERT_CTX_VALID(ctx);
15322
15323 /* -1 = top callstack entry, callstack[callstack_top - 1]
15324 * -callstack_top = bottom callstack entry, callstack[0]
15325 */
15326 if (level >= 0 || -level > (duk_int_t) thr->callstack_top) {
15327 duk_push_undefined(ctx);
15328 return;
15329 }
15330 duk_push_bare_object(ctx);
15331 DUK_ASSERT(level >= -((duk_int_t) thr->callstack_top) && level <= -1);
15332
15333 act = thr->callstack + thr->callstack_top + level;
15334 /* Relevant PC is just before current one because PC is
15335 * post-incremented. This should match what error augment
15336 * code does.
15337 */
15338 pc = duk_hthread_get_act_prev_pc(thr, act);
15339
15340 duk_push_tval(ctx, &act->tv_func);
15341
15342 duk_push_uint(ctx, (duk_uint_t) pc);
15343 duk_put_prop_stridx_short(ctx, -3, DUK_STRIDX_PC);
15344
15345#if defined(DUK_USE_PC2LINE)
15346 line = duk_hobject_pc2line_query(ctx, -1, pc);
15347#else
15348 line = 0;
15349#endif
15350 duk_push_uint(ctx, (duk_uint_t) line);
15351 duk_put_prop_stridx_short(ctx, -3, DUK_STRIDX_LINE_NUMBER);
15352
15353 duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_LC_FUNCTION);
15354 /* Providing access to e.g. act->lex_env would be dangerous: these
15355 * internal structures must never be accessible to the application.
15356 * Duktape relies on them having consistent data, and this consistency
15357 * is only asserted for, not checked for.
15358 */
15359}
15360
15361/* automatic undefs */
15362#undef DUK__IDX_ASIZE
15363#undef DUK__IDX_BCBYTES
15364#undef DUK__IDX_CLASS
15365#undef DUK__IDX_DBYTES
15366#undef DUK__IDX_ENEXT
15367#undef DUK__IDX_ESIZE
15368#undef DUK__IDX_HBYTES
15369#undef DUK__IDX_HSIZE
15370#undef DUK__IDX_ITAG
15371#undef DUK__IDX_PBYTES
15372#undef DUK__IDX_REFC
15373#undef DUK__IDX_TSTATE
15374#undef DUK__IDX_TYPE
15375#undef DUK__IDX_VARIANT
15376/*
15377 * Memory calls.
15378 */
15379
15380/* #include duk_internal.h -> already included */
15381
15382DUK_EXTERNAL void *duk_alloc_raw(duk_context *ctx, duk_size_t size) {
15383 duk_hthread *thr = (duk_hthread *) ctx;
15384
15385 DUK_ASSERT_CTX_VALID(ctx);
15386
15387 return DUK_ALLOC_RAW(thr->heap, size);
15388}
15389
15390DUK_EXTERNAL void duk_free_raw(duk_context *ctx, void *ptr) {
15391 duk_hthread *thr = (duk_hthread *) ctx;
15392
15393 DUK_ASSERT_CTX_VALID(ctx);
15394
15395 DUK_FREE_RAW(thr->heap, ptr);
15396}
15397
15398DUK_EXTERNAL void *duk_realloc_raw(duk_context *ctx, void *ptr, duk_size_t size) {
15399 duk_hthread *thr = (duk_hthread *) ctx;
15400
15401 DUK_ASSERT_CTX_VALID(ctx);
15402
15403 return DUK_REALLOC_RAW(thr->heap, ptr, size);
15404}
15405
15406DUK_EXTERNAL void *duk_alloc(duk_context *ctx, duk_size_t size) {
15407 duk_hthread *thr = (duk_hthread *) ctx;
15408
15409 DUK_ASSERT_CTX_VALID(ctx);
15410
15411 return DUK_ALLOC(thr->heap, size);
15412}
15413
15414DUK_EXTERNAL void duk_free(duk_context *ctx, void *ptr) {
15415 duk_hthread *thr = (duk_hthread *) ctx;
15416
15417 DUK_ASSERT_CTX_VALID(ctx);
15418
15419 DUK_FREE(thr->heap, ptr);
15420}
15421
15422DUK_EXTERNAL void *duk_realloc(duk_context *ctx, void *ptr, duk_size_t size) {
15423 duk_hthread *thr = (duk_hthread *) ctx;
15424
15425 DUK_ASSERT_CTX_VALID(ctx);
15426
15427 /*
15428 * Note: since this is an exposed API call, there should be
15429 * no way a mark-and-sweep could have a side effect on the
15430 * memory allocation behind 'ptr'; the pointer should never
15431 * be something that Duktape wants to change.
15432 *
15433 * Thus, no need to use DUK_REALLOC_INDIRECT (and we don't
15434 * have the storage location here anyway).
15435 */
15436
15437 return DUK_REALLOC(thr->heap, ptr, size);
15438}
15439
15440DUK_EXTERNAL void duk_get_memory_functions(duk_context *ctx, duk_memory_functions *out_funcs) {
15441 duk_hthread *thr = (duk_hthread *) ctx;
15442 duk_heap *heap;
15443
15444 DUK_ASSERT_CTX_VALID(ctx);
15445 DUK_ASSERT(out_funcs != NULL);
15446 DUK_ASSERT(thr != NULL);
15447 DUK_ASSERT(thr->heap != NULL);
15448
15449 heap = thr->heap;
15450 out_funcs->alloc_func = heap->alloc_func;
15451 out_funcs->realloc_func = heap->realloc_func;
15452 out_funcs->free_func = heap->free_func;
15453 out_funcs->udata = heap->heap_udata;
15454}
15455
15456DUK_EXTERNAL void duk_gc(duk_context *ctx, duk_uint_t flags) {
15457 duk_hthread *thr = (duk_hthread *) ctx;
15458 duk_heap *heap;
15459 duk_small_uint_t ms_flags;
15460
15461 DUK_ASSERT_CTX_VALID(ctx);
15462 heap = thr->heap;
15463 DUK_ASSERT(heap != NULL);
15464
15465 DUK_D(DUK_DPRINT("mark-and-sweep requested by application"));
15466 DUK_ASSERT(DUK_GC_COMPACT == DUK_MS_FLAG_EMERGENCY); /* Compact flag is 1:1 with emergency flag which forces compaction. */
15467 ms_flags = (duk_small_uint_t) flags;
15468 duk_heap_mark_and_sweep(heap, ms_flags);
15469}
15470/*
15471 * Object handling: property access and other support functions.
15472 */
15473
15474/* #include duk_internal.h -> already included */
15475
15476/*
15477 * Property handling
15478 *
15479 * The API exposes only the most common property handling functions.
15480 * The caller can invoke Ecmascript built-ins for full control (e.g.
15481 * defineProperty, getOwnPropertyDescriptor).
15482 */
15483
15484DUK_EXTERNAL duk_bool_t duk_get_prop(duk_context *ctx, duk_idx_t obj_idx) {
15485 duk_hthread *thr = (duk_hthread *) ctx;
15486 duk_tval *tv_obj;
15487 duk_tval *tv_key;
15488 duk_bool_t rc;
15489
15490 DUK_ASSERT_CTX_VALID(ctx);
15491
15492 /* Note: copying tv_obj and tv_key to locals to shield against a valstack
15493 * resize is not necessary for a property get right now.
15494 */
15495
15496 tv_obj = duk_require_tval(ctx, obj_idx);
15497 tv_key = duk_require_tval(ctx, -1);
15498
15499 rc = duk_hobject_getprop(thr, tv_obj, tv_key);
15500 DUK_ASSERT(rc == 0 || rc == 1);
15501 /* a value is left on stack regardless of rc */
15502
15503 duk_remove_m2(ctx); /* remove key */
15504 return rc; /* 1 if property found, 0 otherwise */
15505}
15506
15507DUK_EXTERNAL duk_bool_t duk_get_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key) {
15508 DUK_ASSERT_CTX_VALID(ctx);
15509 DUK_ASSERT(key != NULL);
15510
15511 obj_idx = duk_require_normalize_index(ctx, obj_idx);
15512 duk_push_string(ctx, key);
15513 return duk_get_prop(ctx, obj_idx);
15514}
15515
15516DUK_EXTERNAL duk_bool_t duk_get_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
15517 DUK_ASSERT_CTX_VALID(ctx);
15518 DUK_ASSERT(key != NULL);
15519
15520 obj_idx = duk_require_normalize_index(ctx, obj_idx);
15521 duk_push_lstring(ctx, key, key_len);
15522 return duk_get_prop(ctx, obj_idx);
15523}
15524
15525DUK_EXTERNAL duk_bool_t duk_get_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
15526 DUK_ASSERT_CTX_VALID(ctx);
15527
15528 obj_idx = duk_require_normalize_index(ctx, obj_idx);
15529 duk_push_uarridx(ctx, arr_idx);
15530 return duk_get_prop(ctx, obj_idx);
15531}
15532
15533DUK_INTERNAL duk_bool_t duk_get_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx) {
15534 duk_hthread *thr = (duk_hthread *) ctx;
15535
15536 DUK_ASSERT_CTX_VALID(ctx);
15537 DUK_ASSERT_STRIDX_VALID(stridx);
15538 DUK_UNREF(thr);
15539
15540 obj_idx = duk_require_normalize_index(ctx, obj_idx);
15541 duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
15542 return duk_get_prop(ctx, obj_idx);
15543}
15544
15545DUK_INTERNAL duk_bool_t duk_get_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args) {
15546 return duk_get_prop_stridx(ctx, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
15547 (duk_small_uint_t) (packed_args & 0xffffUL));
15548}
15549
15550DUK_INTERNAL duk_bool_t duk_get_prop_stridx_boolean(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_bool_t *out_has_prop) {
15551 duk_bool_t rc;
15552
15553 DUK_ASSERT_CTX_VALID(ctx);
15554 DUK_ASSERT_STRIDX_VALID(stridx);
15555
15556 rc = duk_get_prop_stridx(ctx, obj_idx, stridx);
15557 if (out_has_prop) {
15558 *out_has_prop = rc;
15559 }
15560 rc = duk_to_boolean(ctx, -1);
15561 DUK_ASSERT(rc == 0 || rc == 1);
15562 duk_pop(ctx);
15563 return rc;
15564}
15565
15566DUK_LOCAL duk_bool_t duk__put_prop_shared(duk_context *ctx, duk_idx_t obj_idx, duk_idx_t idx_key) {
15567 duk_hthread *thr = (duk_hthread *) ctx;
15568 duk_tval *tv_obj;
15569 duk_tval *tv_key;
15570 duk_tval *tv_val;
15571 duk_small_int_t throw_flag;
15572 duk_bool_t rc;
15573
15574 /* Note: copying tv_obj and tv_key to locals to shield against a valstack
15575 * resize is not necessary for a property put right now (putprop protects
15576 * against it internally).
15577 */
15578
15579 /* Key and value indices are either (-2, -1) or (-1, -2). Given idx_key,
15580 * idx_val is always (idx_key ^ 0x01).
15581 */
15582 DUK_ASSERT((idx_key == -2 && (idx_key ^ 1) == -1) ||
15583 (idx_key == -1 && (idx_key ^ 1) == -2));
15584 /* XXX: Direct access; faster validation. */
15585 tv_obj = duk_require_tval(ctx, obj_idx);
15586 tv_key = duk_require_tval(ctx, idx_key);
15587 tv_val = duk_require_tval(ctx, idx_key ^ 1);
15588 throw_flag = duk_is_strict_call(ctx);
15589
15590 rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, throw_flag);
15591 DUK_ASSERT(rc == 0 || rc == 1);
15592
15593 duk_pop_2(ctx); /* remove key and value */
15594 return rc; /* 1 if property found, 0 otherwise */
15595}
15596
15597DUK_EXTERNAL duk_bool_t duk_put_prop(duk_context *ctx, duk_idx_t obj_idx) {
15598 DUK_ASSERT_CTX_VALID(ctx);
15599 return duk__put_prop_shared(ctx, obj_idx, -2);
15600}
15601
15602DUK_EXTERNAL duk_bool_t duk_put_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key) {
15603 DUK_ASSERT_CTX_VALID(ctx);
15604 DUK_ASSERT(key != NULL);
15605
15606 /* Careful here and with other duk_put_prop_xxx() helpers: the
15607 * target object and the property value may be in the same value
15608 * stack slot (unusual, but still conceptually clear).
15609 */
15610 obj_idx = duk_normalize_index(ctx, obj_idx);
15611 (void) duk_push_string(ctx, key);
15612 return duk__put_prop_shared(ctx, obj_idx, -1);
15613}
15614
15615DUK_EXTERNAL duk_bool_t duk_put_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
15616 DUK_ASSERT_CTX_VALID(ctx);
15617 DUK_ASSERT(key != NULL);
15618
15619 obj_idx = duk_normalize_index(ctx, obj_idx);
15620 (void) duk_push_lstring(ctx, key, key_len);
15621 return duk__put_prop_shared(ctx, obj_idx, -1);
15622}
15623
15624DUK_EXTERNAL duk_bool_t duk_put_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
15625 DUK_ASSERT_CTX_VALID(ctx);
15626
15627 obj_idx = duk_require_normalize_index(ctx, obj_idx);
15628 duk_push_uarridx(ctx, arr_idx);
15629 return duk__put_prop_shared(ctx, obj_idx, -1);
15630}
15631
15632DUK_INTERNAL duk_bool_t duk_put_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx) {
15633 duk_hthread *thr = (duk_hthread *) ctx;
15634
15635 DUK_ASSERT_CTX_VALID(ctx);
15636 DUK_ASSERT_STRIDX_VALID(stridx);
15637 DUK_UNREF(thr);
15638
15639 obj_idx = duk_require_normalize_index(ctx, obj_idx);
15640 duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
15641 return duk__put_prop_shared(ctx, obj_idx, -1);
15642}
15643
15644DUK_INTERNAL duk_bool_t duk_put_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args) {
15645 return duk_put_prop_stridx(ctx, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
15646 (duk_small_uint_t) (packed_args & 0xffffUL));
15647}
15648
15649DUK_EXTERNAL duk_bool_t duk_del_prop(duk_context *ctx, duk_idx_t obj_idx) {
15650 duk_hthread *thr = (duk_hthread *) ctx;
15651 duk_tval *tv_obj;
15652 duk_tval *tv_key;
15653 duk_small_int_t throw_flag;
15654 duk_bool_t rc;
15655
15656 DUK_ASSERT_CTX_VALID(ctx);
15657
15658 /* Note: copying tv_obj and tv_key to locals to shield against a valstack
15659 * resize is not necessary for a property delete right now.
15660 */
15661
15662 tv_obj = duk_require_tval(ctx, obj_idx);
15663 tv_key = duk_require_tval(ctx, -1);
15664 throw_flag = duk_is_strict_call(ctx);
15665
15666 rc = duk_hobject_delprop(thr, tv_obj, tv_key, throw_flag);
15667 DUK_ASSERT(rc == 0 || rc == 1);
15668
15669 duk_pop(ctx); /* remove key */
15670 return rc;
15671}
15672
15673DUK_EXTERNAL duk_bool_t duk_del_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key) {
15674 DUK_ASSERT_CTX_VALID(ctx);
15675 DUK_ASSERT(key != NULL);
15676
15677 obj_idx = duk_require_normalize_index(ctx, obj_idx);
15678 duk_push_string(ctx, key);
15679 return duk_del_prop(ctx, obj_idx);
15680}
15681
15682DUK_EXTERNAL duk_bool_t duk_del_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
15683 DUK_ASSERT_CTX_VALID(ctx);
15684 DUK_ASSERT(key != NULL);
15685
15686 obj_idx = duk_require_normalize_index(ctx, obj_idx);
15687 duk_push_lstring(ctx, key, key_len);
15688 return duk_del_prop(ctx, obj_idx);
15689}
15690
15691DUK_EXTERNAL duk_bool_t duk_del_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
15692 DUK_ASSERT_CTX_VALID(ctx);
15693
15694 obj_idx = duk_require_normalize_index(ctx, obj_idx);
15695 duk_push_uarridx(ctx, arr_idx);
15696 return duk_del_prop(ctx, obj_idx);
15697}
15698
15699DUK_INTERNAL duk_bool_t duk_del_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx) {
15700 duk_hthread *thr = (duk_hthread *) ctx;
15701
15702 DUK_ASSERT_CTX_VALID(ctx);
15703 DUK_ASSERT_STRIDX_VALID(stridx);
15704 DUK_UNREF(thr);
15705
15706 obj_idx = duk_require_normalize_index(ctx, obj_idx);
15707 duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
15708 return duk_del_prop(ctx, obj_idx);
15709}
15710
15711#if 0
15712DUK_INTERNAL duk_bool_t duk_del_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args) {
15713 return duk_del_prop_stridx(ctx, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
15714 (duk_small_uint_t) (packed_args & 0xffffUL));
15715}
15716#endif
15717
15718DUK_EXTERNAL duk_bool_t duk_has_prop(duk_context *ctx, duk_idx_t obj_idx) {
15719 duk_hthread *thr = (duk_hthread *) ctx;
15720 duk_tval *tv_obj;
15721 duk_tval *tv_key;
15722 duk_bool_t rc;
15723
15724 DUK_ASSERT_CTX_VALID(ctx);
15725
15726 /* Note: copying tv_obj and tv_key to locals to shield against a valstack
15727 * resize is not necessary for a property existence check right now.
15728 */
15729
15730 tv_obj = duk_require_tval(ctx, obj_idx);
15731 tv_key = duk_require_tval(ctx, -1);
15732
15733 rc = duk_hobject_hasprop(thr, tv_obj, tv_key);
15734 DUK_ASSERT(rc == 0 || rc == 1);
15735
15736 duk_pop(ctx); /* remove key */
15737 return rc; /* 1 if property found, 0 otherwise */
15738}
15739
15740DUK_EXTERNAL duk_bool_t duk_has_prop_string(duk_context *ctx, duk_idx_t obj_idx, const char *key) {
15741 DUK_ASSERT_CTX_VALID(ctx);
15742 DUK_ASSERT(key != NULL);
15743
15744 obj_idx = duk_require_normalize_index(ctx, obj_idx);
15745 duk_push_string(ctx, key);
15746 return duk_has_prop(ctx, obj_idx);
15747}
15748
15749DUK_EXTERNAL duk_bool_t duk_has_prop_lstring(duk_context *ctx, duk_idx_t obj_idx, const char *key, duk_size_t key_len) {
15750 DUK_ASSERT_CTX_VALID(ctx);
15751 DUK_ASSERT(key != NULL);
15752
15753 obj_idx = duk_require_normalize_index(ctx, obj_idx);
15754 duk_push_lstring(ctx, key, key_len);
15755 return duk_has_prop(ctx, obj_idx);
15756}
15757
15758DUK_EXTERNAL duk_bool_t duk_has_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx) {
15759 DUK_ASSERT_CTX_VALID(ctx);
15760
15761 obj_idx = duk_require_normalize_index(ctx, obj_idx);
15762 duk_push_uarridx(ctx, arr_idx);
15763 return duk_has_prop(ctx, obj_idx);
15764}
15765
15766DUK_INTERNAL duk_bool_t duk_has_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx) {
15767 duk_hthread *thr = (duk_hthread *) ctx;
15768
15769 DUK_ASSERT_CTX_VALID(ctx);
15770 DUK_ASSERT_STRIDX_VALID(stridx);
15771 DUK_UNREF(thr);
15772
15773 obj_idx = duk_require_normalize_index(ctx, obj_idx);
15774 duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
15775 return duk_has_prop(ctx, obj_idx);
15776}
15777
15778#if 0
15779DUK_INTERNAL duk_bool_t duk_has_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args) {
15780 return duk_has_prop_stridx(ctx, (duk_idx_t) (duk_int16_t) (packed_args >> 16),
15781 (duk_small_uint_t) (packed_args & 0xffffUL));
15782}
15783#endif
15784
15785/* Define own property without inheritance lookups and such. This differs from
15786 * [[DefineOwnProperty]] because special behaviors (like Array 'length') are
15787 * not invoked by this method. The caller must be careful to invoke any such
15788 * behaviors if necessary.
15789 */
15790DUK_INTERNAL void duk_xdef_prop(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t desc_flags) {
15791 duk_hthread *thr = (duk_hthread *) ctx;
15792 duk_hobject *obj;
15794
15795 DUK_ASSERT_CTX_VALID(ctx);
15796
15797 obj = duk_require_hobject(ctx, obj_idx);
15798 DUK_ASSERT(obj != NULL);
15799 key = duk_to_property_key_hstring(ctx, -2);
15800 DUK_ASSERT(key != NULL);
15801 DUK_ASSERT(duk_require_tval(ctx, -1) != NULL);
15802
15803 duk_hobject_define_property_internal(thr, obj, key, desc_flags);
15804
15805 duk_pop(ctx); /* pop key */
15806}
15807
15808DUK_INTERNAL void duk_xdef_prop_index(duk_context *ctx, duk_idx_t obj_idx, duk_uarridx_t arr_idx, duk_small_uint_t desc_flags) {
15809 duk_hthread *thr = (duk_hthread *) ctx;
15810 duk_hobject *obj;
15811
15812 DUK_ASSERT_CTX_VALID(ctx);
15813
15814 obj = duk_require_hobject(ctx, obj_idx);
15815 DUK_ASSERT(obj != NULL);
15816
15817 duk_hobject_define_property_internal_arridx(thr, obj, arr_idx, desc_flags);
15818 /* value popped by call */
15819}
15820
15821DUK_INTERNAL void duk_xdef_prop_stridx(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_uint_t desc_flags) {
15822 duk_hthread *thr = (duk_hthread *) ctx;
15823 duk_hobject *obj;
15825
15826 DUK_ASSERT_CTX_VALID(ctx);
15827 DUK_ASSERT_STRIDX_VALID(stridx);
15828
15829 obj = duk_require_hobject(ctx, obj_idx);
15830 DUK_ASSERT(obj != NULL);
15831 key = DUK_HTHREAD_GET_STRING(thr, stridx);
15832 DUK_ASSERT(key != NULL);
15833 DUK_ASSERT(duk_require_tval(ctx, -1) != NULL);
15834
15835 duk_hobject_define_property_internal(thr, obj, key, desc_flags);
15836 /* value popped by call */
15837}
15838
15839DUK_INTERNAL void duk_xdef_prop_stridx_short_raw(duk_context *ctx, duk_uint_t packed_args) {
15840 duk_xdef_prop_stridx(ctx, (duk_idx_t) (duk_int8_t) (packed_args >> 24),
15841 (duk_small_uint_t) (packed_args >> 8) & 0xffffUL,
15842 (duk_small_uint_t) (packed_args & 0xffL));
15843}
15844
15845DUK_INTERNAL void duk_xdef_prop_stridx_builtin(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx, duk_small_int_t builtin_idx, duk_small_uint_t desc_flags) {
15846 duk_hthread *thr = (duk_hthread *) ctx;
15847 duk_hobject *obj;
15849
15850 DUK_ASSERT_CTX_VALID(ctx);
15851 DUK_ASSERT_STRIDX_VALID(stridx);
15852 DUK_ASSERT_BIDX_VALID(builtin_idx);
15853
15854 obj = duk_require_hobject(ctx, obj_idx);
15855 DUK_ASSERT(obj != NULL);
15856 key = DUK_HTHREAD_GET_STRING(thr, stridx);
15857 DUK_ASSERT(key != NULL);
15858
15859 duk_push_hobject(ctx, thr->builtins[builtin_idx]);
15860 duk_hobject_define_property_internal(thr, obj, key, desc_flags);
15861 /* value popped by call */
15862}
15863
15864/* This is a rare property helper; it sets the global thrower (E5 Section 13.2.3)
15865 * setter/getter into an object property. This is needed by the 'arguments'
15866 * object creation code, function instance creation code, and Function.prototype.bind().
15867 */
15868
15869DUK_INTERNAL void duk_xdef_prop_stridx_thrower(duk_context *ctx, duk_idx_t obj_idx, duk_small_uint_t stridx) {
15870 obj_idx = duk_require_normalize_index(ctx, obj_idx);
15871 duk_push_hstring_stridx(ctx, stridx);
15872 duk_push_hobject_bidx(ctx, DUK_BIDX_TYPE_ERROR_THROWER);
15873 duk_dup_top(ctx);
15874 duk_def_prop(ctx, obj_idx, DUK_DEFPROP_HAVE_SETTER | DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_FORCE); /* attributes always 0 */
15875}
15876
15877/* Object.getOwnPropertyDescriptor() equivalent C binding. */
15878DUK_EXTERNAL void duk_get_prop_desc(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t flags) {
15879 DUK_UNREF(flags); /* no flags defined yet */
15880
15881 duk_hobject_object_get_own_property_descriptor(ctx, obj_idx); /* [ ... key ] -> [ ... desc ] */
15882}
15883
15884/* Object.defineProperty() equivalent C binding. */
15885DUK_EXTERNAL void duk_def_prop(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t flags) {
15886 duk_hthread *thr = (duk_hthread *) ctx;
15887 duk_idx_t idx_base;
15888 duk_hobject *obj;
15890 duk_idx_t idx_value;
15891 duk_hobject *get;
15892 duk_hobject *set;
15893 duk_uint_t is_data_desc;
15894 duk_uint_t is_acc_desc;
15895
15896 DUK_ASSERT_CTX_VALID(ctx);
15897
15898 obj = duk_require_hobject(ctx, obj_idx);
15899
15900 is_data_desc = flags & (DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE);
15901 is_acc_desc = flags & (DUK_DEFPROP_HAVE_GETTER | DUK_DEFPROP_HAVE_SETTER);
15902 if (is_data_desc && is_acc_desc) {
15903 /* "Have" flags must not be conflicting so that they would
15904 * apply to both a plain property and an accessor at the same
15905 * time.
15906 */
15907 goto fail_invalid_desc;
15908 }
15909
15910 idx_base = duk_get_top_index(ctx);
15911 if (flags & DUK_DEFPROP_HAVE_SETTER) {
15912 duk_require_type_mask(ctx, idx_base, DUK_TYPE_MASK_UNDEFINED |
15913 DUK_TYPE_MASK_OBJECT |
15914 DUK_TYPE_MASK_LIGHTFUNC);
15915 set = duk_get_hobject_promote_lfunc(ctx, idx_base);
15916 if (set != NULL && !DUK_HOBJECT_IS_CALLABLE(set)) {
15917 goto fail_not_callable;
15918 }
15919 idx_base--;
15920 } else {
15921 set = NULL;
15922 }
15923 if (flags & DUK_DEFPROP_HAVE_GETTER) {
15924 duk_require_type_mask(ctx, idx_base, DUK_TYPE_MASK_UNDEFINED |
15925 DUK_TYPE_MASK_OBJECT |
15926 DUK_TYPE_MASK_LIGHTFUNC);
15927 get = duk_get_hobject_promote_lfunc(ctx, idx_base);
15928 if (get != NULL && !DUK_HOBJECT_IS_CALLABLE(get)) {
15929 goto fail_not_callable;
15930 }
15931 idx_base--;
15932 } else {
15933 get = NULL;
15934 }
15935 if (flags & DUK_DEFPROP_HAVE_VALUE) {
15936 idx_value = idx_base;
15937 idx_base--;
15938 } else {
15939 idx_value = (duk_idx_t) -1;
15940 }
15941 key = duk_to_property_key_hstring(ctx, idx_base);
15942 DUK_ASSERT(key != NULL);
15943
15944 duk_require_valid_index(ctx, idx_base);
15945
15946 duk_hobject_define_property_helper(ctx,
15947 flags /*defprop_flags*/,
15948 obj,
15949 key,
15950 idx_value,
15951 get,
15952 set,
15953 1 /*throw_flag*/);
15954
15955 /* Clean up stack */
15956
15957 duk_set_top(ctx, idx_base);
15958
15959 /* [ ... obj ... ] */
15960
15961 return;
15962
15963 fail_invalid_desc:
15964 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_DESCRIPTOR);
15965 return;
15966
15967 fail_not_callable:
15968 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE);
15969 return;
15970}
15971
15972/*
15973 * Object related
15974 *
15975 * Note: seal() and freeze() are accessible through Ecmascript bindings,
15976 * and are not exposed through the API.
15977 */
15978
15979DUK_EXTERNAL void duk_compact(duk_context *ctx, duk_idx_t obj_idx) {
15980 duk_hthread *thr = (duk_hthread *) ctx;
15981 duk_hobject *obj;
15982
15983 DUK_ASSERT_CTX_VALID(ctx);
15984
15985 obj = duk_get_hobject(ctx, obj_idx);
15986 if (obj) {
15987 /* Note: this may fail, caller should protect the call if necessary */
15988 duk_hobject_compact_props(thr, obj);
15989 }
15990}
15991
15992DUK_INTERNAL void duk_compact_m1(duk_context *ctx) {
15993 duk_compact(ctx, -1);
15994}
15995
15996/* XXX: the duk_hobject_enum.c stack APIs should be reworked */
15997
15998DUK_EXTERNAL void duk_enum(duk_context *ctx, duk_idx_t obj_idx, duk_uint_t enum_flags) {
15999 DUK_ASSERT_CTX_VALID(ctx);
16000
16001 duk_dup(ctx, obj_idx);
16002 duk_require_hobject_promote_mask(ctx, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
16003 duk_hobject_enumerator_create(ctx, enum_flags); /* [target] -> [enum] */
16004}
16005
16006DUK_EXTERNAL duk_bool_t duk_next(duk_context *ctx, duk_idx_t enum_index, duk_bool_t get_value) {
16007 DUK_ASSERT_CTX_VALID(ctx);
16008
16009 duk_require_hobject(ctx, enum_index);
16010 duk_dup(ctx, enum_index);
16011 return duk_hobject_enumerator_next(ctx, get_value);
16012}
16013
16014/*
16015 * Helpers for writing multiple properties
16016 */
16017
16018DUK_EXTERNAL void duk_put_function_list(duk_context *ctx, duk_idx_t obj_idx, const duk_function_list_entry *funcs) {
16019 const duk_function_list_entry *ent = funcs;
16020
16021 DUK_ASSERT_CTX_VALID(ctx);
16022
16023 obj_idx = duk_require_normalize_index(ctx, obj_idx);
16024 if (ent != NULL) {
16025 while (ent->key != NULL) {
16026 duk_push_c_function(ctx, ent->value, ent->nargs);
16027 duk_put_prop_string(ctx, obj_idx, ent->key);
16028 ent++;
16029 }
16030 }
16031}
16032
16033DUK_EXTERNAL void duk_put_number_list(duk_context *ctx, duk_idx_t obj_idx, const duk_number_list_entry *numbers) {
16034 const duk_number_list_entry *ent = numbers;
16035 duk_tval *tv;
16036
16037 DUK_ASSERT_CTX_VALID(ctx);
16038
16039 obj_idx = duk_require_normalize_index(ctx, obj_idx);
16040 if (ent != NULL) {
16041 while (ent->key != NULL) {
16042 tv = ((duk_hthread *) ctx)->valstack_top++;
16043 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv)); /* value stack init policy */
16044 DUK_TVAL_SET_NUMBER_CHKFAST_SLOW(tv, ent->value); /* no need for decref/incref */
16045 duk_put_prop_string(ctx, obj_idx, ent->key);
16046 ent++;
16047 }
16048 }
16049}
16050
16051/*
16052 * Shortcut for accessing global object properties
16053 */
16054
16055DUK_EXTERNAL duk_bool_t duk_get_global_string(duk_context *ctx, const char *key) {
16056 duk_hthread *thr = (duk_hthread *) ctx;
16057 duk_bool_t ret;
16058
16059 DUK_ASSERT_CTX_VALID(ctx);
16060 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
16061
16062 /* XXX: direct implementation */
16063
16064 duk_push_hobject(ctx, thr->builtins[DUK_BIDX_GLOBAL]);
16065 ret = duk_get_prop_string(ctx, -1, key);
16066 duk_remove_m2(ctx);
16067 return ret;
16068}
16069
16070DUK_EXTERNAL duk_bool_t duk_get_global_lstring(duk_context *ctx, const char *key, duk_size_t key_len) {
16071 duk_hthread *thr = (duk_hthread *) ctx;
16072 duk_bool_t ret;
16073
16074 DUK_ASSERT_CTX_VALID(ctx);
16075 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
16076
16077 /* XXX: direct implementation */
16078
16079 duk_push_hobject(ctx, thr->builtins[DUK_BIDX_GLOBAL]);
16080 ret = duk_get_prop_lstring(ctx, -1, key, key_len);
16081 duk_remove_m2(ctx);
16082 return ret;
16083}
16084
16085DUK_EXTERNAL duk_bool_t duk_put_global_string(duk_context *ctx, const char *key) {
16086 duk_hthread *thr = (duk_hthread *) ctx;
16087 duk_bool_t ret;
16088
16089 DUK_ASSERT_CTX_VALID(ctx);
16090 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
16091
16092 /* XXX: direct implementation */
16093
16094 duk_push_hobject(ctx, thr->builtins[DUK_BIDX_GLOBAL]);
16095 duk_insert(ctx, -2);
16096 ret = duk_put_prop_string(ctx, -2, key); /* [ ... global val ] -> [ ... global ] */
16097 duk_pop(ctx);
16098 return ret;
16099}
16100
16101DUK_EXTERNAL duk_bool_t duk_put_global_lstring(duk_context *ctx, const char *key, duk_size_t key_len) {
16102 duk_hthread *thr = (duk_hthread *) ctx;
16103 duk_bool_t ret;
16104
16105 DUK_ASSERT_CTX_VALID(ctx);
16106 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
16107
16108 /* XXX: direct implementation */
16109
16110 duk_push_hobject(ctx, thr->builtins[DUK_BIDX_GLOBAL]);
16111 duk_insert(ctx, -2);
16112 ret = duk_put_prop_lstring(ctx, -2, key, key_len); /* [ ... global val ] -> [ ... global ] */
16113 duk_pop(ctx);
16114 return ret;
16115}
16116
16117/*
16118 * Object prototype
16119 */
16120
16121DUK_EXTERNAL void duk_get_prototype(duk_context *ctx, duk_idx_t idx) {
16122 duk_hthread *thr = (duk_hthread *) ctx;
16123 duk_hobject *obj;
16124 duk_hobject *proto;
16125
16126 DUK_ASSERT_CTX_VALID(ctx);
16127 DUK_UNREF(thr);
16128
16129 obj = duk_require_hobject(ctx, idx);
16130 DUK_ASSERT(obj != NULL);
16131
16132 /* XXX: shared helper for duk_push_hobject_or_undefined()? */
16133 proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, obj);
16134 if (proto) {
16135 duk_push_hobject(ctx, proto);
16136 } else {
16137 duk_push_undefined(ctx);
16138 }
16139}
16140
16141DUK_EXTERNAL void duk_set_prototype(duk_context *ctx, duk_idx_t idx) {
16142 duk_hthread *thr = (duk_hthread *) ctx;
16143 duk_hobject *obj;
16144 duk_hobject *proto;
16145
16146 DUK_ASSERT_CTX_VALID(ctx);
16147
16148 obj = duk_require_hobject(ctx, idx);
16149 DUK_ASSERT(obj != NULL);
16150 duk_require_type_mask(ctx, -1, DUK_TYPE_MASK_UNDEFINED |
16151 DUK_TYPE_MASK_OBJECT);
16152 proto = duk_get_hobject(ctx, -1);
16153 /* proto can also be NULL here (allowed explicitly) */
16154
16155#if defined(DUK_USE_ROM_OBJECTS)
16156 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
16157 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE); /* XXX: "read only object"? */
16158 return;
16159 }
16160#endif
16161
16162 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, obj, proto);
16163
16164 duk_pop(ctx);
16165}
16166
16167/*
16168 * Object finalizer
16169 */
16170
16171#if defined(DUK_USE_FINALIZER_SUPPORT)
16172/* XXX: these could be implemented as macros calling an internal function
16173 * directly.
16174 * XXX: same issue as with Duktape.fin: there's no way to delete the property
16175 * now (just set it to undefined).
16176 */
16177DUK_EXTERNAL void duk_get_finalizer(duk_context *ctx, duk_idx_t idx) {
16178 DUK_ASSERT_CTX_VALID(ctx);
16179
16180 duk_get_prop_stridx(ctx, idx, DUK_STRIDX_INT_FINALIZER);
16181}
16182
16183DUK_EXTERNAL void duk_set_finalizer(duk_context *ctx, duk_idx_t idx) {
16184 DUK_ASSERT_CTX_VALID(ctx);
16185
16186 duk_put_prop_stridx(ctx, idx, DUK_STRIDX_INT_FINALIZER);
16187}
16188#else /* DUK_USE_FINALIZER_SUPPORT */
16189DUK_EXTERNAL void duk_get_finalizer(duk_context *ctx, duk_idx_t idx) {
16190 DUK_ASSERT_CTX_VALID(ctx);
16191 DUK_UNREF(idx);
16192 DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx);
16193}
16194
16195DUK_EXTERNAL void duk_set_finalizer(duk_context *ctx, duk_idx_t idx) {
16196 DUK_ASSERT_CTX_VALID(ctx);
16197 DUK_UNREF(idx);
16198 DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx);
16199}
16200#endif /* DUK_USE_FINALIZER_SUPPORT */
16201/*
16202 * API calls related to general value stack manipulation: resizing the value
16203 * stack, pushing and popping values, type checking and reading values,
16204 * coercing values, etc.
16205 *
16206 * Also contains internal functions (such as duk_get_tval()), defined
16207 * in duk_api_internal.h, with semantics similar to the public API.
16208 */
16209
16210/* XXX: repetition of stack pre-checks -> helper or macro or inline */
16211/* XXX: shared api error strings, and perhaps even throw code for rare cases? */
16212
16213/* #include duk_internal.h -> already included */
16214
16215/*
16216 * Forward declarations
16217 */
16218
16219DUK_LOCAL_DECL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_uint_t flags);
16220
16221/*
16222 * Global state for working around missing variadic macros
16223 */
16224
16225#if !defined(DUK_USE_VARIADIC_MACROS)
16226DUK_EXTERNAL const char *duk_api_global_filename = NULL;
16227DUK_EXTERNAL duk_int_t duk_api_global_line = 0;
16228#endif
16229
16230/*
16231 * Misc helpers
16232 */
16233
16234#if !defined(DUK_USE_PACKED_TVAL)
16235DUK_LOCAL const duk_uint_t duk__type_from_tag[] = {
16236 DUK_TYPE_NUMBER,
16237 DUK_TYPE_NUMBER, /* fastint */
16238 DUK_TYPE_UNDEFINED,
16239 DUK_TYPE_NULL,
16240 DUK_TYPE_BOOLEAN,
16241 DUK_TYPE_POINTER,
16242 DUK_TYPE_LIGHTFUNC,
16243 DUK_TYPE_NONE,
16244 DUK_TYPE_STRING,
16245 DUK_TYPE_OBJECT,
16246 DUK_TYPE_BUFFER,
16247};
16248DUK_LOCAL const duk_uint_t duk__type_mask_from_tag[] = {
16249 DUK_TYPE_MASK_NUMBER,
16250 DUK_TYPE_MASK_NUMBER, /* fastint */
16251 DUK_TYPE_MASK_UNDEFINED,
16252 DUK_TYPE_MASK_NULL,
16253 DUK_TYPE_MASK_BOOLEAN,
16254 DUK_TYPE_MASK_POINTER,
16255 DUK_TYPE_MASK_LIGHTFUNC,
16256 DUK_TYPE_MASK_NONE,
16257 DUK_TYPE_MASK_STRING,
16258 DUK_TYPE_MASK_OBJECT,
16259 DUK_TYPE_MASK_BUFFER,
16260};
16261#endif /* !DUK_USE_PACKED_TVAL */
16262
16263/* Check that there's room to push one value. */
16264#if defined(DUK_USE_VALSTACK_UNSAFE)
16265/* Faster but value stack overruns are memory unsafe. */
16266#define DUK__CHECK_SPACE() do { \
16267 DUK_ASSERT(!(thr->valstack_top >= thr->valstack_end)); \
16268 } while (0)
16269#else
16270#define DUK__CHECK_SPACE() do { \
16271 if (DUK_UNLIKELY(thr->valstack_top >= thr->valstack_end)) { \
16272 DUK_ERROR_RANGE_PUSH_BEYOND(thr); \
16273 } \
16274 } while (0)
16275#endif
16276
16277DUK_LOCAL_DECL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t idx, duk_uint_t tag);
16278
16279DUK_LOCAL duk_int_t duk__api_coerce_d2i(duk_context *ctx, duk_idx_t idx, duk_bool_t require) {
16280 duk_hthread *thr;
16281 duk_tval *tv;
16282 duk_small_int_t c;
16283 duk_double_t d;
16284
16285 thr = (duk_hthread *) ctx;
16286
16287 tv = duk_get_tval_or_unused(ctx, idx);
16288 DUK_ASSERT(tv != NULL);
16289
16290 /*
16291 * Special cases like NaN and +/- Infinity are handled explicitly
16292 * because a plain C coercion from double to int handles these cases
16293 * in undesirable ways. For instance, NaN may coerce to INT_MIN
16294 * (not zero), and INT_MAX + 1 may coerce to INT_MIN (not INT_MAX).
16295 *
16296 * This double-to-int coercion differs from ToInteger() because it
16297 * has a finite range (ToInteger() allows e.g. +/- Infinity). It
16298 * also differs from ToInt32() because the INT_MIN/INT_MAX clamping
16299 * depends on the size of the int type on the platform. In particular,
16300 * on platforms with a 64-bit int type, the full range is allowed.
16301 */
16302
16303#if defined(DUK_USE_FASTINT)
16304 if (DUK_TVAL_IS_FASTINT(tv)) {
16305 duk_int64_t t = DUK_TVAL_GET_FASTINT(tv);
16306#if (DUK_INT_MAX <= 0x7fffffffL)
16307 /* Clamping only necessary for 32-bit ints. */
16308 if (t < DUK_INT_MIN) {
16309 t = DUK_INT_MIN;
16310 } else if (t > DUK_INT_MAX) {
16311 t = DUK_INT_MAX;
16312 }
16313#endif
16314 return (duk_int_t) t;
16315 }
16316#endif
16317
16318 if (DUK_TVAL_IS_NUMBER(tv)) {
16319 d = DUK_TVAL_GET_NUMBER(tv);
16320 c = (duk_small_int_t) DUK_FPCLASSIFY(d);
16321 if (c == DUK_FP_NAN) {
16322 return 0;
16323 } else if (d < (duk_double_t) DUK_INT_MIN) {
16324 /* covers -Infinity */
16325 return DUK_INT_MIN;
16326 } else if (d > (duk_double_t) DUK_INT_MAX) {
16327 /* covers +Infinity */
16328 return DUK_INT_MAX;
16329 } else {
16330 /* coerce towards zero */
16331 return (duk_int_t) d;
16332 }
16333 }
16334
16335 if (require) {
16336 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER);
16337 /* not reachable */
16338 }
16339 return 0;
16340}
16341
16342DUK_LOCAL duk_uint_t duk__api_coerce_d2ui(duk_context *ctx, duk_idx_t idx, duk_bool_t require) {
16343 duk_hthread *thr;
16344 duk_tval *tv;
16345 duk_small_int_t c;
16346 duk_double_t d;
16347
16348 /* Same as above but for unsigned int range. */
16349
16350 thr = (duk_hthread *) ctx;
16351
16352 tv = duk_get_tval_or_unused(ctx, idx);
16353 DUK_ASSERT(tv != NULL);
16354
16355#if defined(DUK_USE_FASTINT)
16356 if (DUK_TVAL_IS_FASTINT(tv)) {
16357 duk_int64_t t = DUK_TVAL_GET_FASTINT(tv);
16358 if (t < 0) {
16359 t = 0;
16360 }
16361#if (DUK_UINT_MAX <= 0xffffffffUL)
16362 /* Clamping only necessary for 32-bit ints. */
16363 else if (t > DUK_UINT_MAX) {
16364 t = DUK_UINT_MAX;
16365 }
16366#endif
16367 return (duk_uint_t) t;
16368 }
16369#endif
16370
16371 if (DUK_TVAL_IS_NUMBER(tv)) {
16372 d = DUK_TVAL_GET_NUMBER(tv);
16373 c = (duk_small_int_t) DUK_FPCLASSIFY(d);
16374 if (c == DUK_FP_NAN) {
16375 return 0;
16376 } else if (d < 0.0) {
16377 /* covers -Infinity */
16378 return (duk_uint_t) 0;
16379 } else if (d > (duk_double_t) DUK_UINT_MAX) {
16380 /* covers +Infinity */
16381 return (duk_uint_t) DUK_UINT_MAX;
16382 } else {
16383 /* coerce towards zero */
16384 return (duk_uint_t) d;
16385 }
16386 }
16387
16388 if (require) {
16389 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER);
16390 /* not reachable */
16391 }
16392 return 0;
16393}
16394
16395/*
16396 * Stack index validation/normalization and getting a stack duk_tval ptr.
16397 *
16398 * These are called by many API entrypoints so the implementations must be
16399 * fast and "inlined".
16400 *
16401 * There's some repetition because of this; keep the functions in sync.
16402 */
16403
16404DUK_EXTERNAL duk_idx_t duk_normalize_index(duk_context *ctx, duk_idx_t idx) {
16405 duk_hthread *thr = (duk_hthread *) ctx;
16406 duk_uidx_t vs_size;
16407 duk_uidx_t uidx;
16408
16409 DUK_ASSERT_CTX_VALID(ctx);
16410 DUK_ASSERT(DUK_INVALID_INDEX < 0);
16411
16412 /* Care must be taken to avoid pointer wrapping in the index
16413 * validation. For instance, on a 32-bit platform with 8-byte
16414 * duk_tval the index 0x20000000UL would wrap the memory space
16415 * once.
16416 */
16417
16418 /* Assume value stack sizes (in elements) fits into duk_idx_t. */
16419 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
16420 vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
16421 DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
16422
16423 if (idx < 0) {
16424 uidx = vs_size + (duk_uidx_t) idx;
16425 } else {
16426 /* since index non-negative */
16427 DUK_ASSERT(idx != DUK_INVALID_INDEX);
16428 uidx = (duk_uidx_t) idx;
16429 }
16430
16431 /* DUK_INVALID_INDEX won't be accepted as a valid index. */
16432 DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
16433
16434 if (DUK_LIKELY(uidx < vs_size)) {
16435 return (duk_idx_t) uidx;
16436 }
16437 return DUK_INVALID_INDEX;
16438}
16439
16440DUK_EXTERNAL duk_idx_t duk_require_normalize_index(duk_context *ctx, duk_idx_t idx) {
16441 duk_hthread *thr = (duk_hthread *) ctx;
16442 duk_uidx_t vs_size;
16443 duk_uidx_t uidx;
16444
16445 DUK_ASSERT_CTX_VALID(ctx);
16446 DUK_ASSERT(DUK_INVALID_INDEX < 0);
16447
16448 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
16449 vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
16450 DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
16451
16452 if (idx < 0) {
16453 uidx = vs_size + (duk_uidx_t) idx;
16454 } else {
16455 DUK_ASSERT(idx != DUK_INVALID_INDEX);
16456 uidx = (duk_uidx_t) idx;
16457 }
16458
16459 /* DUK_INVALID_INDEX won't be accepted as a valid index. */
16460 DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
16461
16462 if (DUK_LIKELY(uidx < vs_size)) {
16463 return (duk_idx_t) uidx;
16464 }
16465 DUK_ERROR_RANGE_INDEX(thr, idx);
16466 return 0; /* unreachable */
16467}
16468
16469DUK_INTERNAL duk_tval *duk_get_tval(duk_context *ctx, duk_idx_t idx) {
16470 duk_hthread *thr = (duk_hthread *) ctx;
16471 duk_uidx_t vs_size;
16472 duk_uidx_t uidx;
16473
16474 DUK_ASSERT_CTX_VALID(ctx);
16475 DUK_ASSERT(DUK_INVALID_INDEX < 0);
16476
16477 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
16478 vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
16479 DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
16480
16481 if (idx < 0) {
16482 uidx = vs_size + (duk_uidx_t) idx;
16483 } else {
16484 DUK_ASSERT(idx != DUK_INVALID_INDEX);
16485 uidx = (duk_uidx_t) idx;
16486 }
16487
16488 /* DUK_INVALID_INDEX won't be accepted as a valid index. */
16489 DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
16490
16491 if (DUK_LIKELY(uidx < vs_size)) {
16492 return thr->valstack_bottom + uidx;
16493 }
16494 return NULL;
16495}
16496
16497/* Variant of duk_get_tval() which is guaranteed to return a valid duk_tval
16498 * pointer. When duk_get_tval() would return NULL, this variant returns a
16499 * pointer to a duk_tval with tag DUK_TAG_UNUSED. This allows the call site
16500 * to avoid an unnecessary NULL check which sometimes leads to better code.
16501 * The return duk_tval is read only (at least for the UNUSED value).
16502 */
16503DUK_LOCAL const duk_tval_unused duk__const_tval_unused = DUK_TVAL_UNUSED_INITIALIZER();
16504
16505DUK_INTERNAL duk_tval *duk_get_tval_or_unused(duk_context *ctx, duk_idx_t idx) {
16506 duk_tval *tv;
16507 tv = duk_get_tval(ctx, idx);
16508 if (tv != NULL) {
16509 return tv;
16510 }
16511 return (duk_tval *) DUK_LOSE_CONST(&duk__const_tval_unused);
16512}
16513
16514DUK_INTERNAL duk_tval *duk_require_tval(duk_context *ctx, duk_idx_t idx) {
16515 duk_hthread *thr = (duk_hthread *) ctx;
16516 duk_uidx_t vs_size;
16517 duk_uidx_t uidx;
16518
16519 DUK_ASSERT_CTX_VALID(ctx);
16520 DUK_ASSERT(DUK_INVALID_INDEX < 0);
16521
16522 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
16523 vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
16524 DUK_ASSERT_DISABLE(vs_size >= 0); /* unsigned */
16525
16526 /* Use unsigned arithmetic to optimize comparison. */
16527 if (idx < 0) {
16528 uidx = vs_size + (duk_uidx_t) idx;
16529 } else {
16530 DUK_ASSERT(idx != DUK_INVALID_INDEX);
16531 uidx = (duk_uidx_t) idx;
16532 }
16533
16534 /* DUK_INVALID_INDEX won't be accepted as a valid index. */
16535 DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
16536
16537 if (DUK_LIKELY(uidx < vs_size)) {
16538 return thr->valstack_bottom + uidx;
16539 }
16540 DUK_ERROR_RANGE_INDEX(thr, idx);
16541 return NULL;
16542}
16543
16544/* Non-critical. */
16545DUK_EXTERNAL duk_bool_t duk_is_valid_index(duk_context *ctx, duk_idx_t idx) {
16546 DUK_ASSERT_CTX_VALID(ctx);
16547 DUK_ASSERT(DUK_INVALID_INDEX < 0);
16548
16549 return (duk_normalize_index(ctx, idx) >= 0);
16550}
16551
16552/* Non-critical. */
16553DUK_EXTERNAL void duk_require_valid_index(duk_context *ctx, duk_idx_t idx) {
16554 duk_hthread *thr = (duk_hthread *) ctx;
16555
16556 DUK_ASSERT_CTX_VALID(ctx);
16557 DUK_ASSERT(DUK_INVALID_INDEX < 0);
16558
16559 if (duk_normalize_index(ctx, idx) < 0) {
16560 DUK_ERROR_RANGE_INDEX(thr, idx);
16561 return; /* unreachable */
16562 }
16563}
16564
16565/*
16566 * Value stack top handling
16567 */
16568
16569DUK_EXTERNAL duk_idx_t duk_get_top(duk_context *ctx) {
16570 duk_hthread *thr = (duk_hthread *) ctx;
16571
16572 DUK_ASSERT_CTX_VALID(ctx);
16573
16574 return (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
16575}
16576
16577/* Internal helper to get current top but to require a minimum top value
16578 * (TypeError if not met).
16579 */
16580DUK_INTERNAL duk_idx_t duk_get_top_require_min(duk_context *ctx, duk_idx_t min_top) {
16581 duk_hthread *thr = (duk_hthread *) ctx;
16582 duk_idx_t ret;
16583
16584 DUK_ASSERT_CTX_VALID(ctx);
16585
16586 ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
16587 if (ret < min_top) {
16588 DUK_ERROR_TYPE_INVALID_ARGS(thr);
16589 }
16590 return ret;
16591}
16592
16593/* Set stack top within currently allocated range, but don't reallocate.
16594 * This is performance critical especially for call handling, so whenever
16595 * changing, profile and look at generated code.
16596 */
16597DUK_EXTERNAL void duk_set_top(duk_context *ctx, duk_idx_t idx) {
16598 duk_hthread *thr = (duk_hthread *) ctx;
16599 duk_uidx_t vs_size;
16600 duk_uidx_t vs_limit;
16601 duk_uidx_t uidx;
16602 duk_tval *tv;
16603
16604 DUK_ASSERT_CTX_VALID(ctx);
16605 DUK_ASSERT(DUK_INVALID_INDEX < 0);
16606
16607 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
16608 DUK_ASSERT(thr->valstack_end >= thr->valstack_bottom);
16609 vs_size = (duk_uidx_t) (thr->valstack_top - thr->valstack_bottom);
16610 vs_limit = (duk_uidx_t) (thr->valstack_end - thr->valstack_bottom);
16611
16612 if (idx < 0) {
16613 /* Negative indices are always within allocated stack but
16614 * must not go below zero index.
16615 */
16616 uidx = vs_size + (duk_uidx_t) idx;
16617 } else {
16618 /* Positive index can be higher than valstack top but must
16619 * not go above allocated stack (equality is OK).
16620 */
16621 uidx = (duk_uidx_t) idx;
16622 }
16623
16624 /* DUK_INVALID_INDEX won't be accepted as a valid index. */
16625 DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_size);
16626 DUK_ASSERT(vs_size + (duk_uidx_t) DUK_INVALID_INDEX >= vs_limit);
16627
16628#if defined(DUK_USE_VALSTACK_UNSAFE)
16629 DUK_ASSERT(uidx <= vs_limit);
16630 DUK_UNREF(vs_limit);
16631#else
16632 if (DUK_UNLIKELY(uidx > vs_limit)) {
16633 DUK_ERROR_RANGE_INDEX(thr, idx);
16634 return; /* unreachable */
16635 }
16636#endif
16637 DUK_ASSERT(uidx <= vs_limit);
16638
16639 /* Handle change in value stack top. Respect value stack
16640 * initialization policy: 'undefined' above top. Note that
16641 * DECREF may cause a side effect that reallocates valstack,
16642 * so must relookup after DECREF.
16643 */
16644
16645 if (uidx >= vs_size) {
16646 /* Stack size increases or stays the same. */
16647#if defined(DUK_USE_ASSERTIONS)
16648 duk_uidx_t count;
16649
16650 count = uidx - vs_size;
16651 while (count != 0) {
16652 count--;
16653 tv = thr->valstack_top + count;
16654 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv));
16655 }
16656#endif
16657 thr->valstack_top = thr->valstack_bottom + uidx;
16658 } else {
16659 /* Stack size decreases. */
16660#if defined(DUK_USE_REFERENCE_COUNTING)
16661 duk_uidx_t count;
16662 duk_tval *tv_end;
16663
16664 count = vs_size - uidx;
16665 DUK_ASSERT(count > 0);
16666 tv = thr->valstack_top;
16667 tv_end = tv - count;
16668 DUK_ASSERT(tv > tv_end); /* Because count > 0. */
16669 do {
16670 tv--;
16671 DUK_ASSERT(tv >= thr->valstack_bottom);
16672 DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv);
16673 } while (tv != tv_end);
16674 thr->valstack_top = tv_end;
16675 DUK_REFZERO_CHECK_FAST(thr);
16676#else /* DUK_USE_REFERENCE_COUNTING */
16677 duk_uidx_t count;
16678 duk_tval *tv_end;
16679
16680 count = vs_size - uidx;
16681 tv = thr->valstack_top;
16682 tv_end = tv - count;
16683 DUK_ASSERT(tv > tv_end);
16684 do {
16685 tv--;
16686 DUK_TVAL_SET_UNDEFINED(tv);
16687 } while (tv != tv_end);
16688 thr->valstack_top = tv_end;
16689#endif /* DUK_USE_REFERENCE_COUNTING */
16690 }
16691}
16692
16693DUK_EXTERNAL duk_idx_t duk_get_top_index(duk_context *ctx) {
16694 duk_hthread *thr = (duk_hthread *) ctx;
16695 duk_idx_t ret;
16696
16697 DUK_ASSERT_CTX_VALID(ctx);
16698
16699 ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1;
16700 if (DUK_UNLIKELY(ret < 0)) {
16701 /* Return invalid index; if caller uses this without checking
16702 * in another API call, the index won't map to a valid stack
16703 * entry.
16704 */
16705 return DUK_INVALID_INDEX;
16706 }
16707 return ret;
16708}
16709
16710/* Internal variant: call assumes there is at least one element on the value
16711 * stack frame; this is only asserted for.
16712 */
16713DUK_INTERNAL duk_idx_t duk_get_top_index_unsafe(duk_context *ctx) {
16714 duk_hthread *thr = (duk_hthread *) ctx;
16715 duk_idx_t ret;
16716
16717 DUK_ASSERT_CTX_VALID(ctx);
16718
16719 ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1;
16720 return ret;
16721}
16722
16723DUK_EXTERNAL duk_idx_t duk_require_top_index(duk_context *ctx) {
16724 duk_hthread *thr = (duk_hthread *) ctx;
16725 duk_idx_t ret;
16726
16727 DUK_ASSERT_CTX_VALID(ctx);
16728
16729 ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom) - 1;
16730 if (DUK_UNLIKELY(ret < 0)) {
16731 DUK_ERROR_RANGE_INDEX(thr, -1);
16732 return 0; /* unreachable */
16733 }
16734 return ret;
16735}
16736
16737/*
16738 * Value stack resizing.
16739 *
16740 * This resizing happens above the current "top": the value stack can be
16741 * grown or shrunk, but the "top" is not affected. The value stack cannot
16742 * be resized to a size below the current "top".
16743 *
16744 * The low level reallocation primitive must carefully recompute all value
16745 * stack pointers, and must also work if ALL pointers are NULL. The resize
16746 * is quite tricky because the valstack realloc may cause a mark-and-sweep,
16747 * which may run finalizers. Running finalizers may resize the valstack
16748 * recursively (the same value stack we're working on). So, after realloc
16749 * returns, we know that the valstack "top" should still be the same (there
16750 * should not be live values above the "top"), but its underlying size and
16751 * pointer may have changed.
16752 */
16753
16754/* XXX: perhaps refactor this to allow caller to specify some parameters, or
16755 * at least a 'compact' flag which skips any spare or round-up .. useful for
16756 * emergency gc.
16757 */
16758
16759DUK_LOCAL duk_bool_t duk__resize_valstack(duk_context *ctx, duk_size_t new_size) {
16760 duk_hthread *thr = (duk_hthread *) ctx;
16761 duk_ptrdiff_t old_bottom_offset;
16762 duk_ptrdiff_t old_top_offset;
16763 duk_ptrdiff_t old_end_offset_post;
16764#if defined(DUK_USE_DEBUG)
16765 duk_ptrdiff_t old_end_offset_pre;
16766 duk_tval *old_valstack_pre;
16767 duk_tval *old_valstack_post;
16768#endif
16769 duk_tval *new_valstack;
16770 duk_size_t new_alloc_size;
16771 duk_tval *p;
16772
16773 DUK_ASSERT_CTX_VALID(ctx);
16774 DUK_ASSERT(thr != NULL);
16775 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
16776 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
16777 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
16778 DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack) <= new_size); /* can't resize below 'top' */
16779 DUK_ASSERT(new_size <= thr->valstack_max); /* valstack limit caller has check, prevents wrapping */
16780 DUK_ASSERT(new_size <= DUK_SIZE_MAX / sizeof(duk_tval)); /* specific assert for wrapping */
16781
16782 /* get pointer offsets for tweaking below */
16783 old_bottom_offset = (((duk_uint8_t *) thr->valstack_bottom) - ((duk_uint8_t *) thr->valstack));
16784 old_top_offset = (((duk_uint8_t *) thr->valstack_top) - ((duk_uint8_t *) thr->valstack));
16785#if defined(DUK_USE_DEBUG)
16786 old_end_offset_pre = (((duk_uint8_t *) thr->valstack_end) - ((duk_uint8_t *) thr->valstack)); /* not very useful, used for debugging */
16787 old_valstack_pre = thr->valstack;
16788#endif
16789
16790 /* Allocate a new valstack.
16791 *
16792 * Note: cannot use a plain DUK_REALLOC() because a mark-and-sweep may
16793 * invalidate the original thr->valstack base pointer inside the realloc
16794 * process. See doc/memory-management.rst.
16795 */
16796
16797 new_alloc_size = sizeof(duk_tval) * new_size;
16798 new_valstack = (duk_tval *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_valstack_ptr, (void *) thr, new_alloc_size);
16799 if (!new_valstack) {
16800 /* Because new_size != 0, if condition doesn't need to be
16801 * (new_valstack != NULL || new_size == 0).
16802 */
16803 DUK_ASSERT(new_size != 0);
16804 DUK_D(DUK_DPRINT("failed to resize valstack to %lu entries (%lu bytes)",
16805 (unsigned long) new_size, (unsigned long) new_alloc_size));
16806 return 0;
16807 }
16808
16809 /* Note: the realloc may have triggered a mark-and-sweep which may
16810 * have resized our valstack internally. However, the mark-and-sweep
16811 * MUST NOT leave the stack bottom/top in a different state. Particular
16812 * assumptions and facts:
16813 *
16814 * - The thr->valstack pointer may be different after realloc,
16815 * and the offset between thr->valstack_end <-> thr->valstack
16816 * may have changed.
16817 * - The offset between thr->valstack_bottom <-> thr->valstack
16818 * and thr->valstack_top <-> thr->valstack MUST NOT have changed,
16819 * because mark-and-sweep must adhere to a strict stack policy.
16820 * In other words, logical bottom and top MUST NOT have changed.
16821 * - All values above the top are unreachable but are initialized
16822 * to UNDEFINED, up to the post-realloc valstack_end.
16823 * - 'old_end_offset' must be computed after realloc to be correct.
16824 */
16825
16826 DUK_ASSERT((((duk_uint8_t *) thr->valstack_bottom) - ((duk_uint8_t *) thr->valstack)) == old_bottom_offset);
16827 DUK_ASSERT((((duk_uint8_t *) thr->valstack_top) - ((duk_uint8_t *) thr->valstack)) == old_top_offset);
16828
16829 /* success, fixup pointers */
16830 old_end_offset_post = (((duk_uint8_t *) thr->valstack_end) - ((duk_uint8_t *) thr->valstack)); /* must be computed after realloc */
16831#if defined(DUK_USE_DEBUG)
16832 old_valstack_post = thr->valstack;
16833#endif
16834 thr->valstack = new_valstack;
16835 thr->valstack_end = new_valstack + new_size;
16836#if !defined(DUK_USE_PREFER_SIZE)
16837 thr->valstack_size = new_size;
16838#endif
16839 thr->valstack_bottom = (duk_tval *) (void *) ((duk_uint8_t *) new_valstack + old_bottom_offset);
16840 thr->valstack_top = (duk_tval *) (void *) ((duk_uint8_t *) new_valstack + old_top_offset);
16841
16842 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
16843 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
16844 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
16845
16846 /* useful for debugging */
16847#if defined(DUK_USE_DEBUG)
16848 if (old_end_offset_pre != old_end_offset_post) {
16849 DUK_D(DUK_DPRINT("valstack was resized during valstack_resize(), probably by mark-and-sweep; "
16850 "end offset changed: %lu -> %lu",
16851 (unsigned long) old_end_offset_pre,
16852 (unsigned long) old_end_offset_post));
16853 }
16854 if (old_valstack_pre != old_valstack_post) {
16855 DUK_D(DUK_DPRINT("valstack pointer changed during valstack_resize(), probably by mark-and-sweep: %p -> %p",
16856 (void *) old_valstack_pre,
16857 (void *) old_valstack_post));
16858 }
16859#endif
16860
16861 DUK_DD(DUK_DDPRINT("resized valstack to %lu elements (%lu bytes), bottom=%ld, top=%ld, "
16862 "new pointers: start=%p end=%p bottom=%p top=%p",
16863 (unsigned long) new_size, (unsigned long) new_alloc_size,
16864 (long) (thr->valstack_bottom - thr->valstack),
16865 (long) (thr->valstack_top - thr->valstack),
16866 (void *) thr->valstack, (void *) thr->valstack_end,
16867 (void *) thr->valstack_bottom, (void *) thr->valstack_top));
16868
16869 /* Init newly allocated slots (only). */
16870 p = (duk_tval *) (void *) ((duk_uint8_t *) thr->valstack + old_end_offset_post);
16871 while (p < thr->valstack_end) {
16872 /* Never executed if new size is smaller. */
16873 DUK_TVAL_SET_UNDEFINED(p);
16874 p++;
16875 }
16876
16877 /* Assert for value stack initialization policy. */
16878#if defined(DUK_USE_ASSERTIONS)
16879 p = thr->valstack_top;
16880 while (p < thr->valstack_end) {
16881 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(p));
16882 p++;
16883 }
16884#endif
16885
16886 return 1;
16887}
16888
16889DUK_INTERNAL
16890duk_bool_t duk_valstack_resize_raw(duk_context *ctx,
16891 duk_size_t min_new_size,
16892 duk_small_uint_t flags) {
16893 duk_hthread *thr = (duk_hthread *) ctx;
16894 duk_size_t old_size;
16895 duk_size_t new_size;
16896 duk_bool_t is_shrink = 0;
16897 duk_small_uint_t shrink_flag = (flags & DUK_VSRESIZE_FLAG_SHRINK);
16898 duk_small_uint_t compact_flag = (flags & DUK_VSRESIZE_FLAG_COMPACT);
16899 duk_small_uint_t throw_flag = (flags & DUK_VSRESIZE_FLAG_THROW);
16900
16901 DUK_DDD(DUK_DDDPRINT("check valstack resize: min_new_size=%lu, curr_size=%ld, curr_top=%ld, "
16902 "curr_bottom=%ld, shrink=%d, compact=%d, throw=%d",
16903 (unsigned long) min_new_size,
16904 (long) (thr->valstack_end - thr->valstack),
16905 (long) (thr->valstack_top - thr->valstack),
16906 (long) (thr->valstack_bottom - thr->valstack),
16907 (int) shrink_flag, (int) compact_flag, (int) throw_flag));
16908
16909 DUK_ASSERT_CTX_VALID(ctx);
16910 DUK_ASSERT(thr != NULL);
16911 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
16912 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
16913 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
16914
16915#if defined(DUK_USE_PREFER_SIZE)
16916 old_size = (duk_size_t) (thr->valstack_end - thr->valstack);
16917#else
16918 DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack) == thr->valstack_size);
16919 old_size = thr->valstack_size;
16920#endif
16921
16922 if (min_new_size <= old_size) {
16923 is_shrink = 1;
16924 if (!shrink_flag ||
16925 old_size - min_new_size < DUK_VALSTACK_SHRINK_THRESHOLD) {
16926 DUK_DDD(DUK_DDDPRINT("no need to grow or shrink valstack"));
16927 return 1;
16928 }
16929 }
16930
16931 new_size = min_new_size;
16932 if (!compact_flag) {
16933 if (is_shrink) {
16934 /* shrink case; leave some spare */
16935 new_size += DUK_VALSTACK_SHRINK_SPARE;
16936 }
16937
16938 /* round up roughly to next 'grow step' */
16939 new_size = (new_size / DUK_VALSTACK_GROW_STEP + 1) * DUK_VALSTACK_GROW_STEP;
16940 }
16941
16942 DUK_DD(DUK_DDPRINT("want to %s valstack: %lu -> %lu elements (min_new_size %lu)",
16943 (const char *) (new_size > old_size ? "grow" : "shrink"),
16944 (unsigned long) old_size, (unsigned long) new_size,
16945 (unsigned long) min_new_size));
16946
16947 if (new_size > thr->valstack_max) {
16948 /* Note: may be triggered even if minimal new_size would not reach the limit,
16949 * plan limit accordingly (taking DUK_VALSTACK_GROW_STEP into account).
16950 */
16951 if (throw_flag) {
16952 DUK_ERROR_RANGE(thr, DUK_STR_VALSTACK_LIMIT);
16953 } else {
16954 return 0;
16955 }
16956 }
16957
16958 /*
16959 * When resizing the valstack, a mark-and-sweep may be triggered for
16960 * the allocation of the new valstack. If the mark-and-sweep needs
16961 * to use our thread for something, it may cause *the same valstack*
16962 * to be resized recursively. This happens e.g. when mark-and-sweep
16963 * finalizers are called. This is taken into account carefully in
16964 * duk__resize_valstack().
16965 *
16966 * 'new_size' is known to be <= valstack_max, which ensures that
16967 * size_t and pointer arithmetic won't wrap in duk__resize_valstack().
16968 */
16969
16970 if (!duk__resize_valstack(ctx, new_size)) {
16971 if (is_shrink) {
16972 DUK_DD(DUK_DDPRINT("valstack resize failed, but is a shrink, ignore"));
16973 return 1;
16974 }
16975
16976 DUK_DD(DUK_DDPRINT("valstack resize failed"));
16977
16978 if (throw_flag) {
16979 DUK_ERROR_ALLOC_FAILED(thr);
16980 } else {
16981 return 0;
16982 }
16983 }
16984
16985 DUK_DDD(DUK_DDDPRINT("valstack resize successful"));
16986 return 1;
16987}
16988
16989DUK_EXTERNAL duk_bool_t duk_check_stack(duk_context *ctx, duk_idx_t extra) {
16990 duk_hthread *thr = (duk_hthread *) ctx;
16991 duk_size_t min_new_size;
16992
16993 DUK_ASSERT_CTX_VALID(ctx);
16994 DUK_ASSERT(thr != NULL);
16995
16996 if (DUK_UNLIKELY(extra < 0)) {
16997 /* Clamping to zero makes the API more robust to calling code
16998 * calculation errors.
16999 */
17000 extra = 0;
17001 }
17002
17003 min_new_size = (thr->valstack_top - thr->valstack) + extra + DUK_VALSTACK_INTERNAL_EXTRA;
17004 return duk_valstack_resize_raw(ctx,
17005 min_new_size, /* min_new_size */
17006 0 /* no shrink */ | /* flags */
17007 0 /* no compact */ |
17008 0 /* no throw */);
17009}
17010
17011DUK_EXTERNAL void duk_require_stack(duk_context *ctx, duk_idx_t extra) {
17012 duk_hthread *thr = (duk_hthread *) ctx;
17013 duk_size_t min_new_size;
17014
17015 DUK_ASSERT_CTX_VALID(ctx);
17016 DUK_ASSERT(thr != NULL);
17017
17018 if (DUK_UNLIKELY(extra < 0)) {
17019 /* Clamping to zero makes the API more robust to calling code
17020 * calculation errors.
17021 */
17022 extra = 0;
17023 }
17024
17025 min_new_size = (thr->valstack_top - thr->valstack) + extra + DUK_VALSTACK_INTERNAL_EXTRA;
17026 (void) duk_valstack_resize_raw(ctx,
17027 min_new_size, /* min_new_size */
17028 0 /* no shrink */ | /* flags */
17029 0 /* no compact */ |
17030 DUK_VSRESIZE_FLAG_THROW);
17031}
17032
17033DUK_EXTERNAL duk_bool_t duk_check_stack_top(duk_context *ctx, duk_idx_t top) {
17034 duk_size_t min_new_size;
17035
17036 DUK_ASSERT_CTX_VALID(ctx);
17037
17038 if (DUK_UNLIKELY(top < 0)) {
17039 /* Clamping to zero makes the API more robust to calling code
17040 * calculation errors.
17041 */
17042 top = 0;
17043 }
17044
17045 min_new_size = top + DUK_VALSTACK_INTERNAL_EXTRA;
17046 return duk_valstack_resize_raw(ctx,
17047 min_new_size, /* min_new_size */
17048 0 /* no shrink */ | /* flags */
17049 0 /* no compact */ |
17050 0 /* no throw */);
17051}
17052
17053DUK_EXTERNAL void duk_require_stack_top(duk_context *ctx, duk_idx_t top) {
17054 duk_size_t min_new_size;
17055
17056 DUK_ASSERT_CTX_VALID(ctx);
17057
17058 if (DUK_UNLIKELY(top < 0)) {
17059 /* Clamping to zero makes the API more robust to calling code
17060 * calculation errors.
17061 */
17062 top = 0;
17063 }
17064
17065 min_new_size = top + DUK_VALSTACK_INTERNAL_EXTRA;
17066 (void) duk_valstack_resize_raw(ctx,
17067 min_new_size, /* min_new_size */
17068 0 /* no shrink */ | /* flags */
17069 0 /* no compact */ |
17070 DUK_VSRESIZE_FLAG_THROW);
17071}
17072
17073/*
17074 * Basic stack manipulation: swap, dup, insert, replace, etc
17075 */
17076
17077DUK_EXTERNAL void duk_swap(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2) {
17078 duk_tval *tv1;
17079 duk_tval *tv2;
17080 duk_tval tv_tmp;
17081
17082 DUK_ASSERT_CTX_VALID(ctx);
17083
17084 tv1 = duk_require_tval(ctx, idx1);
17085 DUK_ASSERT(tv1 != NULL);
17086 tv2 = duk_require_tval(ctx, idx2);
17087 DUK_ASSERT(tv2 != NULL);
17088
17089 /* If tv1==tv2 this is a NOP, no check is needed */
17090 DUK_TVAL_SET_TVAL(&tv_tmp, tv1);
17091 DUK_TVAL_SET_TVAL(tv1, tv2);
17092 DUK_TVAL_SET_TVAL(tv2, &tv_tmp);
17093}
17094
17095DUK_EXTERNAL void duk_swap_top(duk_context *ctx, duk_idx_t idx) {
17096 DUK_ASSERT_CTX_VALID(ctx);
17097
17098 duk_swap(ctx, idx, -1);
17099}
17100
17101DUK_EXTERNAL void duk_dup(duk_context *ctx, duk_idx_t from_idx) {
17102 duk_hthread *thr;
17103 duk_tval *tv_from;
17104 duk_tval *tv_to;
17105
17106 DUK_ASSERT_CTX_VALID(ctx);
17107 thr = (duk_hthread *) ctx;
17108 DUK__CHECK_SPACE();
17109
17110 tv_from = duk_require_tval(ctx, from_idx);
17111 tv_to = thr->valstack_top++;
17112 DUK_ASSERT(tv_from != NULL);
17113 DUK_ASSERT(tv_to != NULL);
17114 DUK_TVAL_SET_TVAL(tv_to, tv_from);
17115 DUK_TVAL_INCREF(thr, tv_to); /* no side effects */
17116}
17117
17118DUK_EXTERNAL void duk_dup_top(duk_context *ctx) {
17119#if defined(DUK_USE_PREFER_SIZE)
17120 duk_dup(ctx, -1);
17121#else
17122 duk_hthread *thr;
17123 duk_tval *tv_from;
17124 duk_tval *tv_to;
17125
17126 DUK_ASSERT_CTX_VALID(ctx);
17127 thr = (duk_hthread *) ctx;
17128 DUK__CHECK_SPACE();
17129
17130 if (thr->valstack_top - thr->valstack_bottom <= 0) {
17131 DUK_ERROR_RANGE_INDEX(thr, -1);
17132 return; /* unreachable */
17133 }
17134 tv_from = thr->valstack_top - 1;
17135 tv_to = thr->valstack_top++;
17136 DUK_ASSERT(tv_from != NULL);
17137 DUK_ASSERT(tv_to != NULL);
17138 DUK_TVAL_SET_TVAL(tv_to, tv_from);
17139 DUK_TVAL_INCREF(thr, tv_to); /* no side effects */
17140#endif
17141}
17142
17143DUK_INTERNAL void duk_dup_0(duk_context *ctx) {
17144 duk_dup(ctx, 0);
17145}
17146DUK_INTERNAL void duk_dup_1(duk_context *ctx) {
17147 duk_dup(ctx, 1);
17148}
17149DUK_INTERNAL void duk_dup_2(duk_context *ctx) {
17150 duk_dup(ctx, 2);
17151}
17152DUK_INTERNAL void duk_dup_m2(duk_context *ctx) {
17153 duk_dup(ctx, -2);
17154}
17155DUK_INTERNAL void duk_dup_m3(duk_context *ctx) {
17156 duk_dup(ctx, -3);
17157}
17158DUK_INTERNAL void duk_dup_m4(duk_context *ctx) {
17159 duk_dup(ctx, -4);
17160}
17161
17162DUK_EXTERNAL void duk_insert(duk_context *ctx, duk_idx_t to_idx) {
17163 duk_tval *p;
17164 duk_tval *q;
17165 duk_tval tv_tmp;
17166 duk_size_t nbytes;
17167
17168 DUK_ASSERT_CTX_VALID(ctx);
17169
17170 p = duk_require_tval(ctx, to_idx);
17171 DUK_ASSERT(p != NULL);
17172 q = duk_require_tval(ctx, -1);
17173 DUK_ASSERT(q != NULL);
17174
17175 DUK_ASSERT(q >= p);
17176
17177 /* nbytes
17178 * <--------->
17179 * [ ... | p | x | x | q ]
17180 * => [ ... | q | p | x | x ]
17181 */
17182
17183 nbytes = (duk_size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p)); /* Note: 'q' is top-1 */
17184
17185 DUK_DDD(DUK_DDDPRINT("duk_insert: to_idx=%ld, p=%p, q=%p, nbytes=%lu",
17186 (long) to_idx, (void *) p, (void *) q, (unsigned long) nbytes));
17187
17188 /* No net refcount changes. */
17189
17190 if (nbytes > 0) {
17191 DUK_TVAL_SET_TVAL(&tv_tmp, q);
17192 DUK_ASSERT(nbytes > 0);
17193 DUK_MEMMOVE((void *) (p + 1), (const void *) p, (size_t) nbytes);
17194 DUK_TVAL_SET_TVAL(p, &tv_tmp);
17195 } else {
17196 /* nop: insert top to top */
17197 DUK_ASSERT(nbytes == 0);
17198 DUK_ASSERT(p == q);
17199 }
17200}
17201
17202DUK_EXTERNAL void duk_replace(duk_context *ctx, duk_idx_t to_idx) {
17203 duk_hthread *thr = (duk_hthread *) ctx;
17204 duk_tval *tv1;
17205 duk_tval *tv2;
17206 duk_tval tv_tmp;
17207
17208 DUK_ASSERT_CTX_VALID(ctx);
17209
17210 tv1 = duk_require_tval(ctx, -1);
17211 DUK_ASSERT(tv1 != NULL);
17212 tv2 = duk_require_tval(ctx, to_idx);
17213 DUK_ASSERT(tv2 != NULL);
17214
17215 /* For tv1 == tv2, both pointing to stack top, the end result
17216 * is same as duk_pop(ctx).
17217 */
17218 DUK_TVAL_SET_TVAL(&tv_tmp, tv2);
17219 DUK_TVAL_SET_TVAL(tv2, tv1);
17220 DUK_TVAL_SET_UNDEFINED(tv1);
17221 thr->valstack_top--;
17222 DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
17223}
17224
17225DUK_EXTERNAL void duk_copy(duk_context *ctx, duk_idx_t from_idx, duk_idx_t to_idx) {
17226 duk_hthread *thr = (duk_hthread *) ctx;
17227 duk_tval *tv1;
17228 duk_tval *tv2;
17229
17230 DUK_ASSERT_CTX_VALID(ctx);
17231 DUK_UNREF(thr); /* w/o refcounting */
17232
17233 tv1 = duk_require_tval(ctx, from_idx);
17234 DUK_ASSERT(tv1 != NULL);
17235 tv2 = duk_require_tval(ctx, to_idx);
17236 DUK_ASSERT(tv2 != NULL);
17237
17238 /* For tv1 == tv2, this is a no-op (no explicit check needed). */
17239 DUK_TVAL_SET_TVAL_UPDREF(thr, tv2, tv1); /* side effects */
17240}
17241
17242DUK_EXTERNAL void duk_remove(duk_context *ctx, duk_idx_t idx) {
17243 duk_hthread *thr = (duk_hthread *) ctx;
17244 duk_tval *p;
17245 duk_tval *q;
17246#if defined(DUK_USE_REFERENCE_COUNTING)
17247 duk_tval tv_tmp;
17248#endif
17249 duk_size_t nbytes;
17250
17251 DUK_ASSERT_CTX_VALID(ctx);
17252
17253 p = duk_require_tval(ctx, idx);
17254 DUK_ASSERT(p != NULL);
17255 q = duk_require_tval(ctx, -1);
17256 DUK_ASSERT(q != NULL);
17257
17258 DUK_ASSERT(q >= p);
17259
17260 /* nbytes zero size case
17261 * <--------->
17262 * [ ... | p | x | x | q ] [ ... | p==q ]
17263 * => [ ... | x | x | q ] [ ... ]
17264 */
17265
17266#if defined(DUK_USE_REFERENCE_COUNTING)
17267 /* use a temp: decref only when valstack reachable values are correct */
17268 DUK_TVAL_SET_TVAL(&tv_tmp, p);
17269#endif
17270
17271 nbytes = (duk_size_t) (((duk_uint8_t *) q) - ((duk_uint8_t *) p)); /* Note: 'q' is top-1 */
17272 DUK_MEMMOVE((void *) p, (const void *) (p + 1), (size_t) nbytes); /* zero size not an issue: pointers are valid */
17273
17274 DUK_TVAL_SET_UNDEFINED(q);
17275 thr->valstack_top--;
17276
17277#if defined(DUK_USE_REFERENCE_COUNTING)
17278 DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
17279#endif
17280}
17281
17282DUK_INTERNAL_DECL void duk_remove_m2(duk_context *ctx) {
17283 duk_remove(ctx, -2);
17284}
17285
17286/*
17287 * Stack slice primitives
17288 */
17289
17290DUK_EXTERNAL void duk_xcopymove_raw(duk_context *to_ctx, duk_context *from_ctx, duk_idx_t count, duk_bool_t is_copy) {
17291 duk_hthread *to_thr = (duk_hthread *) to_ctx;
17292 duk_hthread *from_thr = (duk_hthread *) from_ctx;
17293 void *src;
17294 duk_size_t nbytes;
17295 duk_tval *p;
17296 duk_tval *q;
17297
17298 /* XXX: several pointer comparison issues here */
17299
17300 DUK_ASSERT_CTX_VALID(to_ctx);
17301 DUK_ASSERT_CTX_VALID(from_ctx);
17302 DUK_ASSERT(to_ctx != NULL);
17303 DUK_ASSERT(from_ctx != NULL);
17304
17305 if (to_ctx == from_ctx) {
17306 DUK_ERROR_TYPE(to_thr, DUK_STR_INVALID_CONTEXT);
17307 return;
17308 }
17309 if ((count < 0) ||
17310 (count > (duk_idx_t) to_thr->valstack_max)) {
17311 /* Maximum value check ensures 'nbytes' won't wrap below. */
17312 DUK_ERROR_RANGE_INVALID_COUNT(to_thr);
17313 return;
17314 }
17315
17316 nbytes = sizeof(duk_tval) * count;
17317 if (nbytes == 0) {
17318 return;
17319 }
17320 DUK_ASSERT(to_thr->valstack_top <= to_thr->valstack_end);
17321 if ((duk_size_t) ((duk_uint8_t *) to_thr->valstack_end - (duk_uint8_t *) to_thr->valstack_top) < nbytes) {
17322 DUK_ERROR_RANGE_PUSH_BEYOND(to_thr);
17323 }
17324 src = (void *) ((duk_uint8_t *) from_thr->valstack_top - nbytes);
17325 if (src < (void *) from_thr->valstack_bottom) {
17326 DUK_ERROR_RANGE_INVALID_COUNT(to_thr);
17327 }
17328
17329 /* copy values (no overlap even if to_ctx == from_ctx; that's not
17330 * allowed now anyway)
17331 */
17332 DUK_ASSERT(nbytes > 0);
17333 DUK_MEMCPY((void *) to_thr->valstack_top, (const void *) src, (size_t) nbytes);
17334
17335 p = to_thr->valstack_top;
17336 to_thr->valstack_top = (duk_tval *) (void *) (((duk_uint8_t *) p) + nbytes);
17337
17338 if (is_copy) {
17339 /* Incref copies, keep originals. */
17340 q = to_thr->valstack_top;
17341 while (p < q) {
17342 DUK_TVAL_INCREF(to_thr, p); /* no side effects */
17343 p++;
17344 }
17345 } else {
17346 /* No net refcount change. */
17347 p = from_thr->valstack_top;
17348 q = (duk_tval *) (void *) (((duk_uint8_t *) p) - nbytes);
17349 from_thr->valstack_top = q;
17350
17351 while (p > q) {
17352 p--;
17353 DUK_TVAL_SET_UNDEFINED(p);
17354 /* XXX: fast primitive to set a bunch of values to UNDEFINED */
17355 }
17356 }
17357}
17358
17359/*
17360 * Get/require
17361 */
17362
17363DUK_EXTERNAL void duk_require_undefined(duk_context *ctx, duk_idx_t idx) {
17364 duk_hthread *thr = (duk_hthread *) ctx;
17365 duk_tval *tv;
17366
17367 DUK_ASSERT_CTX_VALID(ctx);
17368
17369 tv = duk_get_tval_or_unused(ctx, idx);
17370 DUK_ASSERT(tv != NULL);
17371 if (!DUK_TVAL_IS_UNDEFINED(tv)) {
17372 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "undefined", DUK_STR_NOT_UNDEFINED);
17373 }
17374}
17375
17376DUK_EXTERNAL void duk_require_null(duk_context *ctx, duk_idx_t idx) {
17377 duk_hthread *thr = (duk_hthread *) ctx;
17378 duk_tval *tv;
17379
17380 DUK_ASSERT_CTX_VALID(ctx);
17381
17382 tv = duk_get_tval_or_unused(ctx, idx);
17383 DUK_ASSERT(tv != NULL);
17384 if (!DUK_TVAL_IS_NULL(tv)) {
17385 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "null", DUK_STR_NOT_NULL);
17386 }
17387}
17388
17389DUK_EXTERNAL duk_bool_t duk_get_boolean(duk_context *ctx, duk_idx_t idx) {
17390 duk_bool_t ret = 0; /* default: false */
17391 duk_tval *tv;
17392
17393 DUK_ASSERT_CTX_VALID(ctx);
17394
17395 tv = duk_get_tval_or_unused(ctx, idx);
17396 DUK_ASSERT(tv != NULL);
17397 if (DUK_TVAL_IS_BOOLEAN(tv)) {
17398 ret = DUK_TVAL_GET_BOOLEAN(tv);
17399 }
17400
17401 DUK_ASSERT(ret == 0 || ret == 1);
17402 return ret;
17403}
17404
17405DUK_EXTERNAL duk_bool_t duk_require_boolean(duk_context *ctx, duk_idx_t idx) {
17406 duk_hthread *thr = (duk_hthread *) ctx;
17407 duk_tval *tv;
17408 duk_bool_t ret;
17409
17410 DUK_ASSERT_CTX_VALID(ctx);
17411
17412 tv = duk_get_tval_or_unused(ctx, idx);
17413 DUK_ASSERT(tv != NULL);
17414 if (!DUK_TVAL_IS_BOOLEAN(tv)) {
17415 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "boolean", DUK_STR_NOT_BOOLEAN);
17416 }
17417 ret = DUK_TVAL_GET_BOOLEAN(tv);
17418 DUK_ASSERT(ret == 0 || ret == 1);
17419 return ret;
17420}
17421
17422DUK_EXTERNAL duk_double_t duk_get_number(duk_context *ctx, duk_idx_t idx) {
17423 duk_double_union ret;
17424 duk_tval *tv;
17425
17426 DUK_ASSERT_CTX_VALID(ctx);
17427
17428 ret.d = DUK_DOUBLE_NAN; /* default: NaN */
17429 tv = duk_get_tval_or_unused(ctx, idx);
17430 DUK_ASSERT(tv != NULL);
17431 if (DUK_TVAL_IS_NUMBER(tv)) {
17432 ret.d = DUK_TVAL_GET_NUMBER(tv);
17433 }
17434
17435 /* When using packed duk_tval, number must be in NaN-normalized form
17436 * for it to be a duk_tval, so no need to normalize. NOP for unpacked
17437 * duk_tval.
17438 */
17439 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&ret));
17440 return ret.d;
17441}
17442
17443DUK_EXTERNAL duk_double_t duk_require_number(duk_context *ctx, duk_idx_t idx) {
17444 duk_hthread *thr = (duk_hthread *) ctx;
17445 duk_tval *tv;
17446 duk_double_union ret;
17447
17448 DUK_ASSERT_CTX_VALID(ctx);
17449
17450 tv = duk_get_tval_or_unused(ctx, idx);
17451 DUK_ASSERT(tv != NULL);
17452 if (!DUK_TVAL_IS_NUMBER(tv)) {
17453 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "number", DUK_STR_NOT_NUMBER);
17454 }
17455
17456 ret.d = DUK_TVAL_GET_NUMBER(tv);
17457
17458 /* When using packed duk_tval, number must be in NaN-normalized form
17459 * for it to be a duk_tval, so no need to normalize. NOP for unpacked
17460 * duk_tval.
17461 */
17462 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&ret));
17463 return ret.d;
17464}
17465
17466DUK_EXTERNAL duk_int_t duk_get_int(duk_context *ctx, duk_idx_t idx) {
17467 /* Custom coercion for API */
17468 DUK_ASSERT_CTX_VALID(ctx);
17469 return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*require*/);
17470}
17471
17472DUK_EXTERNAL duk_uint_t duk_get_uint(duk_context *ctx, duk_idx_t idx) {
17473 /* Custom coercion for API */
17474 DUK_ASSERT_CTX_VALID(ctx);
17475 return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*require*/);
17476}
17477
17478DUK_EXTERNAL duk_int_t duk_require_int(duk_context *ctx, duk_idx_t idx) {
17479 /* Custom coercion for API */
17480 DUK_ASSERT_CTX_VALID(ctx);
17481 return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 1 /*require*/);
17482}
17483
17484DUK_EXTERNAL duk_uint_t duk_require_uint(duk_context *ctx, duk_idx_t idx) {
17485 /* Custom coercion for API */
17486 DUK_ASSERT_CTX_VALID(ctx);
17487 return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 1 /*require*/);
17488}
17489
17490DUK_EXTERNAL const char *duk_get_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len) {
17491 const char *ret;
17492 duk_tval *tv;
17493
17494 DUK_ASSERT_CTX_VALID(ctx);
17495
17496 /* default: NULL, length 0 */
17497 ret = NULL;
17498 if (out_len) {
17499 *out_len = 0;
17500 }
17501
17502 tv = duk_get_tval_or_unused(ctx, idx);
17503 DUK_ASSERT(tv != NULL);
17504 if (DUK_TVAL_IS_STRING(tv)) {
17505 /* Here we rely on duk_hstring instances always being zero
17506 * terminated even if the actual string is not.
17507 */
17508 duk_hstring *h = DUK_TVAL_GET_STRING(tv);
17509 DUK_ASSERT(h != NULL);
17510 ret = (const char *) DUK_HSTRING_GET_DATA(h);
17511 if (out_len) {
17512 *out_len = DUK_HSTRING_GET_BYTELEN(h);
17513 }
17514 }
17515
17516 return ret;
17517}
17518
17519DUK_EXTERNAL const char *duk_require_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len) {
17520 duk_hstring *h;
17521
17522 DUK_ASSERT_CTX_VALID(ctx);
17523
17524 h = duk_require_hstring(ctx, idx);
17525 DUK_ASSERT(h != NULL);
17526 if (out_len) {
17527 *out_len = DUK_HSTRING_GET_BYTELEN(h);
17528 }
17529 return (const char *) DUK_HSTRING_GET_DATA(h);
17530}
17531
17532DUK_INTERNAL const char *duk_require_lstring_notsymbol(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len) {
17533 duk_hstring *h;
17534
17535 DUK_ASSERT_CTX_VALID(ctx);
17536
17537 h = duk_require_hstring_notsymbol(ctx, idx);
17538 DUK_ASSERT(h != NULL);
17539 if (out_len) {
17540 *out_len = DUK_HSTRING_GET_BYTELEN(h);
17541 }
17542 return (const char *) DUK_HSTRING_GET_DATA(h);
17543}
17544
17545DUK_EXTERNAL const char *duk_get_string(duk_context *ctx, duk_idx_t idx) {
17546 DUK_ASSERT_CTX_VALID(ctx);
17547
17548 return duk_get_lstring(ctx, idx, NULL);
17549}
17550
17551DUK_INTERNAL const char *duk_get_string_notsymbol(duk_context *ctx, duk_idx_t idx) {
17552 duk_hstring *h;
17553
17554 DUK_ASSERT_CTX_VALID(ctx);
17555
17556 h = duk_get_hstring_notsymbol(ctx, idx);
17557 if (h) {
17558 return (const char *) DUK_HSTRING_GET_DATA(h);
17559 } else {
17560 return NULL;
17561 }
17562}
17563
17564DUK_EXTERNAL const char *duk_require_string(duk_context *ctx, duk_idx_t idx) {
17565 DUK_ASSERT_CTX_VALID(ctx);
17566
17567 return duk_require_lstring(ctx, idx, NULL);
17568}
17569
17570DUK_INTERNAL const char *duk_require_string_notsymbol(duk_context *ctx, duk_idx_t idx) {
17571 duk_hstring *h;
17572
17573 DUK_ASSERT_CTX_VALID(ctx);
17574
17575 h = duk_require_hstring_notsymbol(ctx, idx);
17576 DUK_ASSERT(h != NULL);
17577 return (const char *) DUK_HSTRING_GET_DATA(h);
17578}
17579
17580DUK_EXTERNAL void *duk_get_pointer(duk_context *ctx, duk_idx_t idx) {
17581 duk_tval *tv;
17582 void *p;
17583
17584 DUK_ASSERT_CTX_VALID(ctx);
17585
17586 tv = duk_get_tval_or_unused(ctx, idx);
17587 DUK_ASSERT(tv != NULL);
17588 if (!DUK_TVAL_IS_POINTER(tv)) {
17589 return NULL;
17590 }
17591
17592 p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */
17593 return p;
17594}
17595
17596DUK_EXTERNAL void *duk_require_pointer(duk_context *ctx, duk_idx_t idx) {
17597 duk_hthread *thr = (duk_hthread *) ctx;
17598 duk_tval *tv;
17599 void *p;
17600
17601 DUK_ASSERT_CTX_VALID(ctx);
17602
17603 /* Note: here we must be wary of the fact that a pointer may be
17604 * valid and be a NULL.
17605 */
17606 tv = duk_get_tval_or_unused(ctx, idx);
17607 DUK_ASSERT(tv != NULL);
17608 if (!DUK_TVAL_IS_POINTER(tv)) {
17609 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "pointer", DUK_STR_NOT_POINTER);
17610 }
17611 p = DUK_TVAL_GET_POINTER(tv); /* may be NULL */
17612 return p;
17613}
17614
17615#if 0 /*unused*/
17616DUK_INTERNAL void *duk_get_voidptr(duk_context *ctx, duk_idx_t idx) {
17617 duk_tval *tv;
17618 duk_heaphdr *h;
17619
17620 DUK_ASSERT_CTX_VALID(ctx);
17621
17622 tv = duk_get_tval_or_unused(ctx, idx);
17623 DUK_ASSERT(tv != NULL);
17624 if (!DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
17625 return NULL;
17626 }
17627
17628 h = DUK_TVAL_GET_HEAPHDR(tv);
17629 DUK_ASSERT(h != NULL);
17630 return (void *) h;
17631}
17632#endif
17633
17634DUK_LOCAL void *duk__get_buffer_helper(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_bool_t throw_flag) {
17635 duk_hthread *thr = (duk_hthread *) ctx;
17636 duk_tval *tv;
17637 duk_hbuffer *h;
17638
17639 DUK_ASSERT_CTX_VALID(ctx);
17640 DUK_UNREF(thr);
17641
17642 if (out_size != NULL) {
17643 *out_size = 0;
17644 }
17645
17646 tv = duk_get_tval_or_unused(ctx, idx);
17647 DUK_ASSERT(tv != NULL);
17648 if (!DUK_TVAL_IS_BUFFER(tv)) {
17649 if (throw_flag) {
17650 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER);
17651 }
17652 return NULL;
17653 }
17654
17655 h = DUK_TVAL_GET_BUFFER(tv);
17656 DUK_ASSERT(h != NULL);
17657 if (out_size) {
17658 *out_size = DUK_HBUFFER_GET_SIZE(h);
17659 }
17660 return (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); /* may be NULL (but only if size is 0) */
17661}
17662
17663DUK_EXTERNAL void *duk_get_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) {
17664 return duk__get_buffer_helper(ctx, idx, out_size, 0 /*throw_flag*/);
17665}
17666
17667DUK_EXTERNAL void *duk_require_buffer(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) {
17668 return duk__get_buffer_helper(ctx, idx, out_size, 1 /*throw_flag*/);
17669}
17670
17671/* Get the active buffer data area for a plain buffer or a buffer object.
17672 * Return NULL if the the value is not a buffer. Note that a buffer may
17673 * have a NULL data pointer when its size is zero, the optional 'out_isbuffer'
17674 * argument allows caller to detect this reliably.
17675 */
17676DUK_INTERNAL void *duk_get_buffer_data_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_bool_t throw_flag, duk_bool_t *out_isbuffer) {
17677 duk_hthread *thr = (duk_hthread *) ctx;
17678 duk_tval *tv;
17679
17680 DUK_ASSERT_CTX_VALID(ctx);
17681 DUK_UNREF(thr);
17682
17683 if (out_isbuffer != NULL) {
17684 *out_isbuffer = 0;
17685 }
17686 if (out_size != NULL) {
17687 *out_size = 0;
17688 }
17689
17690 tv = duk_get_tval_or_unused(ctx, idx);
17691 DUK_ASSERT(tv != NULL);
17692
17693 if (DUK_TVAL_IS_BUFFER(tv)) {
17694 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
17695 DUK_ASSERT(h != NULL);
17696 if (out_size != NULL) {
17697 *out_size = DUK_HBUFFER_GET_SIZE(h);
17698 }
17699 if (out_isbuffer != NULL) {
17700 *out_isbuffer = 1;
17701 }
17702 return (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h); /* may be NULL (but only if size is 0) */
17703 }
17704#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
17705 else if (DUK_TVAL_IS_OBJECT(tv)) {
17706 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
17707 DUK_ASSERT(h != NULL);
17708 if (DUK_HOBJECT_IS_BUFOBJ(h)) {
17709 /* XXX: this is probably a useful shared helper: for a
17710 * duk_hbufobj, get a validated buffer pointer/length.
17711 */
17712 duk_hbufobj *h_bufobj = (duk_hbufobj *) h;
17713 DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
17714
17715 if (h_bufobj->buf != NULL &&
17716 DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) {
17717 duk_uint8_t *p;
17718
17719 p = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf);
17720 if (out_size != NULL) {
17721 *out_size = (duk_size_t) h_bufobj->length;
17722 }
17723 if (out_isbuffer != NULL) {
17724 *out_isbuffer = 1;
17725 }
17726 return (void *) (p + h_bufobj->offset);
17727 }
17728 /* if slice not fully valid, treat as error */
17729 }
17730 }
17731#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
17732
17733 if (throw_flag) {
17734 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "buffer", DUK_STR_NOT_BUFFER);
17735 }
17736 return NULL;
17737}
17738
17739DUK_EXTERNAL void *duk_get_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) {
17740 return duk_get_buffer_data_raw(ctx, idx, out_size, 0 /*throw_flag*/, NULL);
17741}
17742
17743DUK_EXTERNAL void *duk_require_buffer_data(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size) {
17744 return duk_get_buffer_data_raw(ctx, idx, out_size, 1 /*throw_flag*/, NULL);
17745}
17746
17747/* Raw helper for getting a value from the stack, checking its tag.
17748 * The tag cannot be a number because numbers don't have an internal
17749 * tag in the packed representation.
17750 */
17751
17752DUK_LOCAL duk_heaphdr *duk__get_tagged_heaphdr_raw(duk_context *ctx, duk_idx_t idx, duk_uint_t tag) {
17753 duk_tval *tv;
17754 duk_heaphdr *ret;
17755
17756 DUK_ASSERT_CTX_VALID(ctx);
17757
17758 tv = duk_get_tval_or_unused(ctx, idx);
17759 DUK_ASSERT(tv != NULL);
17760 if (DUK_TVAL_GET_TAG(tv) != tag) {
17761 return (duk_heaphdr *) NULL;
17762 }
17763
17764 ret = DUK_TVAL_GET_HEAPHDR(tv);
17765 DUK_ASSERT(ret != NULL); /* tagged null pointers should never occur */
17766 return ret;
17767
17768}
17769
17770DUK_INTERNAL duk_hstring *duk_get_hstring(duk_context *ctx, duk_idx_t idx) {
17771 return (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_STRING);
17772}
17773
17774DUK_INTERNAL duk_hstring *duk_get_hstring_notsymbol(duk_context *ctx, duk_idx_t idx) {
17775 duk_hstring *res = (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_STRING);
17776 if (res && DUK_HSTRING_HAS_SYMBOL(res)) {
17777 return NULL;
17778 }
17779 return res;
17780}
17781
17782DUK_INTERNAL duk_hstring *duk_require_hstring(duk_context *ctx, duk_idx_t idx) {
17783 duk_hstring *h;
17784 h = (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_STRING);
17785 if (h == NULL) {
17786 DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "string", DUK_STR_NOT_STRING);
17787 }
17788 return h;
17789}
17790
17791DUK_INTERNAL duk_hstring *duk_require_hstring_notsymbol(duk_context *ctx, duk_idx_t idx) {
17792 duk_hstring *h;
17793 h = (duk_hstring *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_STRING);
17794 if (h == NULL || DUK_HSTRING_HAS_SYMBOL(h)) {
17795 DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "string", DUK_STR_NOT_STRING);
17796 }
17797 return h;
17798}
17799
17800DUK_INTERNAL duk_hobject *duk_get_hobject(duk_context *ctx, duk_idx_t idx) {
17801 return (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT);
17802}
17803
17804DUK_INTERNAL duk_hobject *duk_require_hobject(duk_context *ctx, duk_idx_t idx) {
17805 duk_hobject *h;
17806 h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT);
17807 if (h == NULL) {
17808 DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "object", DUK_STR_NOT_OBJECT);
17809 }
17810 return h;
17811}
17812
17813DUK_INTERNAL duk_hbuffer *duk_get_hbuffer(duk_context *ctx, duk_idx_t idx) {
17814 return (duk_hbuffer *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_BUFFER);
17815}
17816
17817DUK_INTERNAL duk_hbuffer *duk_require_hbuffer(duk_context *ctx, duk_idx_t idx) {
17818 duk_hbuffer *h;
17819 h = (duk_hbuffer *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_BUFFER);
17820 if (h == NULL) {
17821 DUK_ERROR_REQUIRE_TYPE_INDEX(ctx, idx, "buffer", DUK_STR_NOT_BUFFER);
17822 }
17823 return h;
17824}
17825
17826DUK_INTERNAL duk_hthread *duk_get_hthread(duk_context *ctx, duk_idx_t idx) {
17827 duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT);
17828 if (h != NULL && !DUK_HOBJECT_IS_THREAD(h)) {
17829 h = NULL;
17830 }
17831 return (duk_hthread *) h;
17832}
17833
17834DUK_INTERNAL duk_hthread *duk_require_hthread(duk_context *ctx, duk_idx_t idx) {
17835 duk_hthread *thr = (duk_hthread *) ctx;
17836 duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT);
17837 if (!(h != NULL && DUK_HOBJECT_IS_THREAD(h))) {
17838 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "thread", DUK_STR_NOT_THREAD);
17839 }
17840 return (duk_hthread *) h;
17841}
17842
17843DUK_INTERNAL duk_hcompfunc *duk_get_hcompfunc(duk_context *ctx, duk_idx_t idx) {
17844 duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT);
17845 if (h != NULL && !DUK_HOBJECT_IS_COMPFUNC(h)) {
17846 h = NULL;
17847 }
17848 return (duk_hcompfunc *) h;
17849}
17850
17851DUK_INTERNAL duk_hcompfunc *duk_require_hcompfunc(duk_context *ctx, duk_idx_t idx) {
17852 duk_hthread *thr = (duk_hthread *) ctx;
17853 duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT);
17854 if (!(h != NULL && DUK_HOBJECT_IS_COMPFUNC(h))) {
17855 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "compiledfunction", DUK_STR_NOT_COMPFUNC);
17856 }
17857 return (duk_hcompfunc *) h;
17858}
17859
17860DUK_INTERNAL duk_hnatfunc *duk_get_hnatfunc(duk_context *ctx, duk_idx_t idx) {
17861 duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT);
17862 if (h != NULL && !DUK_HOBJECT_IS_NATFUNC(h)) {
17863 h = NULL;
17864 }
17865 return (duk_hnatfunc *) h;
17866}
17867
17868DUK_INTERNAL duk_hnatfunc *duk_require_hnatfunc(duk_context *ctx, duk_idx_t idx) {
17869 duk_hthread *thr = (duk_hthread *) ctx;
17870 duk_hobject *h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT);
17871 if (!(h != NULL && DUK_HOBJECT_IS_NATFUNC(h))) {
17872 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC);
17873 }
17874 return (duk_hnatfunc *) h;
17875}
17876
17877DUK_EXTERNAL duk_c_function duk_get_c_function(duk_context *ctx, duk_idx_t idx) {
17878 duk_tval *tv;
17879 duk_hobject *h;
17880 duk_hnatfunc *f;
17881
17882 DUK_ASSERT_CTX_VALID(ctx);
17883
17884 tv = duk_get_tval_or_unused(ctx, idx);
17885 DUK_ASSERT(tv != NULL);
17886 if (!DUK_TVAL_IS_OBJECT(tv)) {
17887 return NULL;
17888 }
17889 h = DUK_TVAL_GET_OBJECT(tv);
17890 DUK_ASSERT(h != NULL);
17891
17892 if (!DUK_HOBJECT_IS_NATFUNC(h)) {
17893 return NULL;
17894 }
17895 DUK_ASSERT(DUK_HOBJECT_HAS_NATFUNC(h));
17896 f = (duk_hnatfunc *) h;
17897
17898 return f->func;
17899}
17900
17901DUK_EXTERNAL duk_c_function duk_require_c_function(duk_context *ctx, duk_idx_t idx) {
17902 duk_hthread *thr = (duk_hthread *) ctx;
17903 duk_c_function ret;
17904
17905 DUK_ASSERT_CTX_VALID(ctx);
17906
17907 ret = duk_get_c_function(ctx, idx);
17908 if (!ret) {
17909 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "nativefunction", DUK_STR_NOT_NATFUNC);
17910 }
17911 return ret;
17912}
17913
17914DUK_EXTERNAL void duk_require_function(duk_context *ctx, duk_idx_t idx) {
17915 if (!duk_is_function(ctx, idx)) {
17916 DUK_ERROR_REQUIRE_TYPE_INDEX((duk_hthread *) ctx, idx, "function", DUK_STR_NOT_FUNCTION);
17917 }
17918}
17919
17920DUK_INTERNAL_DECL void duk_require_constructable(duk_context *ctx, duk_idx_t idx) {
17921 duk_hobject *h;
17922
17923 h = duk_require_hobject_accept_mask(ctx, idx, DUK_TYPE_MASK_LIGHTFUNC);
17924 if (h != NULL && !DUK_HOBJECT_HAS_CONSTRUCTABLE(h)) {
17925 DUK_ERROR_REQUIRE_TYPE_INDEX((duk_hthread *) ctx, idx, "constructable", DUK_STR_NOT_CONSTRUCTABLE);
17926 }
17927 /* Lightfuncs (h == NULL) are constructable. */
17928}
17929
17930DUK_EXTERNAL duk_context *duk_get_context(duk_context *ctx, duk_idx_t idx) {
17931 DUK_ASSERT_CTX_VALID(ctx);
17932
17933 return (duk_context *) duk_get_hthread(ctx, idx);
17934}
17935
17936DUK_EXTERNAL duk_context *duk_require_context(duk_context *ctx, duk_idx_t idx) {
17937 DUK_ASSERT_CTX_VALID(ctx);
17938
17939 return (duk_context *) duk_require_hthread(ctx, idx);
17940}
17941
17942DUK_EXTERNAL void *duk_get_heapptr(duk_context *ctx, duk_idx_t idx) {
17943 duk_tval *tv;
17944 void *ret;
17945
17946 DUK_ASSERT_CTX_VALID(ctx);
17947
17948 tv = duk_get_tval_or_unused(ctx, idx);
17949 DUK_ASSERT(tv != NULL);
17950 if (!DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
17951 return (void *) NULL;
17952 }
17953
17954 ret = (void *) DUK_TVAL_GET_HEAPHDR(tv);
17955 DUK_ASSERT(ret != NULL);
17956 return ret;
17957}
17958
17959DUK_EXTERNAL void *duk_require_heapptr(duk_context *ctx, duk_idx_t idx) {
17960 duk_hthread *thr = (duk_hthread *) ctx;
17961 duk_tval *tv;
17962 void *ret;
17963
17964 DUK_ASSERT_CTX_VALID(ctx);
17965
17966 tv = duk_get_tval_or_unused(ctx, idx);
17967 DUK_ASSERT(tv != NULL);
17968 if (!DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
17969 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, "heapobject", DUK_STR_UNEXPECTED_TYPE);
17970 }
17971
17972 ret = (void *) DUK_TVAL_GET_HEAPHDR(tv);
17973 DUK_ASSERT(ret != NULL);
17974 return ret;
17975}
17976
17977/* Internal helper for getting/requiring a duk_hobject with possible promotion. */
17978DUK_LOCAL duk_hobject *duk__get_hobject_promote_mask_raw(duk_context *ctx, duk_idx_t idx, duk_uint_t type_mask) {
17979 duk_uint_t val_mask;
17980 duk_hobject *res;
17981
17982 DUK_ASSERT_CTX_VALID(ctx);
17983
17984 res = duk_get_hobject(ctx, idx); /* common case, not promoted */
17985 if (res != NULL) {
17986 DUK_ASSERT(res != NULL);
17987 return res;
17988 }
17989
17990 val_mask = duk_get_type_mask(ctx, idx);
17991 if (val_mask & type_mask) {
17992 if (type_mask & DUK_TYPE_MASK_PROMOTE) {
17993 res = duk_to_hobject(ctx, idx);
17994 DUK_ASSERT(res != NULL);
17995 return res;
17996 } else {
17997 return NULL; /* accept without promoting */
17998 }
17999 }
18000
18001 if (type_mask & DUK_TYPE_MASK_THROW) {
18002 DUK_ERROR_REQUIRE_TYPE_INDEX((duk_hthread *) ctx, idx, "object", DUK_STR_NOT_OBJECT);
18003 }
18004 return NULL;
18005}
18006
18007/* Get a duk_hobject * at 'idx'; if the value is not an object but matches the
18008 * supplied 'type_mask', promote it to an object and return the duk_hobject *.
18009 * This is useful for call sites which want an object but also accept a plain
18010 * buffer and/or a lightfunc which gets automatically promoted to an object.
18011 * Return value is NULL if value is neither an object nor a plain type allowed
18012 * by the mask.
18013 */
18014DUK_INTERNAL duk_hobject *duk_get_hobject_promote_mask(duk_context *ctx, duk_idx_t idx, duk_uint_t type_mask) {
18015 return duk__get_hobject_promote_mask_raw(ctx, idx, type_mask | DUK_TYPE_MASK_PROMOTE);
18016}
18017
18018/* Like duk_get_hobject_promote_mask() but throw a TypeError instead of
18019 * returning a NULL.
18020 */
18021DUK_INTERNAL duk_hobject *duk_require_hobject_promote_mask(duk_context *ctx, duk_idx_t idx, duk_uint_t type_mask) {
18022 return duk__get_hobject_promote_mask_raw(ctx, idx, type_mask | DUK_TYPE_MASK_THROW | DUK_TYPE_MASK_PROMOTE);
18023}
18024
18025/* Require a duk_hobject * at 'idx'; if the value is not an object but matches the
18026 * supplied 'type_mask', return a NULL instead. Otherwise throw a TypeError.
18027 */
18028DUK_INTERNAL duk_hobject *duk_require_hobject_accept_mask(duk_context *ctx, duk_idx_t idx, duk_uint_t type_mask) {
18029 return duk__get_hobject_promote_mask_raw(ctx, idx, type_mask | DUK_TYPE_MASK_THROW);
18030}
18031
18032DUK_INTERNAL duk_hobject *duk_get_hobject_with_class(duk_context *ctx, duk_idx_t idx, duk_small_uint_t classnum) {
18033 duk_hobject *h;
18034
18035 DUK_ASSERT_CTX_VALID(ctx);
18036 DUK_ASSERT_DISABLE(classnum >= 0); /* unsigned */
18037 DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX);
18038
18039 h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT);
18040 if (h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) != classnum) {
18041 h = NULL;
18042 }
18043 return h;
18044}
18045
18046DUK_INTERNAL duk_hobject *duk_require_hobject_with_class(duk_context *ctx, duk_idx_t idx, duk_small_uint_t classnum) {
18047 duk_hthread *thr;
18048 duk_hobject *h;
18049
18050 DUK_ASSERT_CTX_VALID(ctx);
18051 DUK_ASSERT_DISABLE(classnum >= 0); /* unsigned */
18052 DUK_ASSERT(classnum <= DUK_HOBJECT_CLASS_MAX);
18053 thr = (duk_hthread *) ctx;
18054
18055 h = (duk_hobject *) duk__get_tagged_heaphdr_raw(ctx, idx, DUK_TAG_OBJECT);
18056 if (!(h != NULL && DUK_HOBJECT_GET_CLASS_NUMBER(h) == classnum)) {
18057 duk_hstring *h_class;
18058 h_class = DUK_HTHREAD_GET_STRING(thr, DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum));
18059 DUK_UNREF(h_class);
18060
18061 DUK_ERROR_REQUIRE_TYPE_INDEX(thr, idx, (const char *) DUK_HSTRING_GET_DATA(h_class), DUK_STR_UNEXPECTED_TYPE);
18062 }
18063 return h;
18064}
18065
18066DUK_EXTERNAL duk_size_t duk_get_length(duk_context *ctx, duk_idx_t idx) {
18067 duk_tval *tv;
18068
18069 DUK_ASSERT_CTX_VALID(ctx);
18070
18071 tv = duk_get_tval_or_unused(ctx, idx);
18072 DUK_ASSERT(tv != NULL);
18073
18074 switch (DUK_TVAL_GET_TAG(tv)) {
18075 case DUK_TAG_UNDEFINED:
18076 case DUK_TAG_NULL:
18077 case DUK_TAG_BOOLEAN:
18078 case DUK_TAG_POINTER:
18079 return 0;
18080#if defined(DUK_USE_PREFER_SIZE)
18081 /* All of these types (besides object) have a virtual, non-configurable
18082 * .length property which is within size_t range so we can just look it
18083 * up without specific type checks.
18084 */
18085 case DUK_TAG_STRING:
18086 case DUK_TAG_BUFFER:
18087 case DUK_TAG_LIGHTFUNC: {
18088 duk_size_t ret;
18089 duk_get_prop_stridx(ctx, idx, DUK_STRIDX_LENGTH);
18090 ret = (duk_size_t) duk_to_number_m1(ctx);
18091 duk_pop(ctx);
18092 return ret;
18093 }
18094#else /* DUK_USE_PREFER_SIZE */
18095 case DUK_TAG_STRING: {
18096 duk_hstring *h = DUK_TVAL_GET_STRING(tv);
18097 DUK_ASSERT(h != NULL);
18098 if (DUK_HSTRING_HAS_SYMBOL(h)) {
18099 return 0;
18100 }
18101 return (duk_size_t) DUK_HSTRING_GET_CHARLEN(h);
18102 }
18103 case DUK_TAG_BUFFER: {
18104 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
18105 DUK_ASSERT(h != NULL);
18106 return (duk_size_t) DUK_HBUFFER_GET_SIZE(h);
18107 }
18108 case DUK_TAG_LIGHTFUNC: {
18109 duk_small_uint_t lf_flags;
18110 lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv);
18111 return (duk_size_t) DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
18112 }
18113#endif /* DUK_USE_PREFER_SIZE */
18114 case DUK_TAG_OBJECT: {
18115 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
18116 DUK_ASSERT(h != NULL);
18117 return (duk_size_t) duk_hobject_get_length((duk_hthread *) ctx, h);
18118 }
18119#if defined(DUK_USE_FASTINT)
18120 case DUK_TAG_FASTINT:
18121#endif
18122 default:
18123 /* number or 'unused' */
18124 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv) || DUK_TVAL_IS_UNUSED(tv));
18125 return 0;
18126 }
18127
18128 DUK_UNREACHABLE();
18129}
18130
18131/*
18132 * duk_known_xxx() helpers
18133 *
18134 * Used internally when we're 100% sure that a certain index is valid and
18135 * contains an object of a certain type. For example, if we duk_push_object()
18136 * we can then safely duk_known_hobject(ctx, -1). These helpers just assert
18137 * for the index and type, and if the assumptions are not valid, memory unsafe
18138 * behavior happens.
18139 */
18140
18141DUK_LOCAL duk_heaphdr *duk__known_heaphdr(duk_context *ctx, duk_idx_t idx) {
18142 duk_hthread *thr = (duk_hthread *) ctx;
18143 duk_tval *tv;
18144 duk_heaphdr *h;
18145
18146 DUK_ASSERT_CTX_VALID(ctx);
18147 if (idx < 0) {
18148 tv = thr->valstack_top + idx;
18149 } else {
18150 tv = thr->valstack_bottom + idx;
18151 }
18152 DUK_ASSERT(tv >= thr->valstack_bottom);
18153 DUK_ASSERT(tv < thr->valstack_top);
18154 h = DUK_TVAL_GET_HEAPHDR(tv);
18155 DUK_ASSERT(h != NULL);
18156 return h;
18157}
18158
18159DUK_INTERNAL duk_hstring *duk_known_hstring(duk_context *ctx, duk_idx_t idx) {
18160 DUK_ASSERT(duk_get_hstring(ctx, idx) != NULL);
18161 return (duk_hstring *) duk__known_heaphdr(ctx, idx);
18162}
18163
18164DUK_INTERNAL duk_hobject *duk_known_hobject(duk_context *ctx, duk_idx_t idx) {
18165 DUK_ASSERT(duk_get_hobject(ctx, idx) != NULL);
18166 return (duk_hobject *) duk__known_heaphdr(ctx, idx);
18167}
18168
18169DUK_INTERNAL duk_hbuffer *duk_known_hbuffer(duk_context *ctx, duk_idx_t idx) {
18170 DUK_ASSERT(duk_get_hbuffer(ctx, idx) != NULL);
18171 return (duk_hbuffer *) duk__known_heaphdr(ctx, idx);
18172}
18173
18174DUK_INTERNAL duk_hcompfunc *duk_known_hcompfunc(duk_context *ctx, duk_idx_t idx) {
18175 DUK_ASSERT(duk_get_hcompfunc(ctx, idx) != NULL);
18176 return (duk_hcompfunc *) duk__known_heaphdr(ctx, idx);
18177}
18178
18179DUK_INTERNAL duk_hnatfunc *duk_known_hnatfunc(duk_context *ctx, duk_idx_t idx) {
18180 DUK_ASSERT(duk_get_hnatfunc(ctx, idx) != NULL);
18181 return (duk_hnatfunc *) duk__known_heaphdr(ctx, idx);
18182}
18183
18184DUK_EXTERNAL void duk_set_length(duk_context *ctx, duk_idx_t idx, duk_size_t len) {
18185 DUK_ASSERT_CTX_VALID(ctx);
18186
18187 idx = duk_normalize_index(ctx, idx);
18188 duk_push_uint(ctx, (duk_uint_t) len);
18189 duk_put_prop_stridx(ctx, idx, DUK_STRIDX_LENGTH);
18190}
18191
18192/*
18193 * Conversions and coercions
18194 *
18195 * The conversion/coercions are in-place operations on the value stack.
18196 * Some operations are implemented here directly, while others call a
18197 * helper in duk_js_ops.c after validating arguments.
18198 */
18199
18200/* E5 Section 8.12.8 */
18201
18202DUK_LOCAL duk_bool_t duk__defaultvalue_coerce_attempt(duk_context *ctx, duk_idx_t idx, duk_small_int_t func_stridx) {
18203 if (duk_get_prop_stridx(ctx, idx, func_stridx)) {
18204 /* [ ... func ] */
18205 if (duk_is_callable(ctx, -1)) {
18206 duk_dup(ctx, idx); /* -> [ ... func this ] */
18207 duk_call_method(ctx, 0); /* -> [ ... retval ] */
18208 if (duk_is_primitive(ctx, -1)) {
18209 duk_replace(ctx, idx);
18210 return 1;
18211 }
18212 /* [ ... retval ]; popped below */
18213 }
18214 }
18215 duk_pop(ctx); /* [ ... func/retval ] -> [ ... ] */
18216 return 0;
18217}
18218
18219DUK_EXTERNAL void duk_to_undefined(duk_context *ctx, duk_idx_t idx) {
18220 duk_hthread *thr = (duk_hthread *) ctx;
18221 duk_tval *tv;
18222
18223 DUK_ASSERT_CTX_VALID(ctx);
18224 DUK_UNREF(thr);
18225
18226 tv = duk_require_tval(ctx, idx);
18227 DUK_ASSERT(tv != NULL);
18228 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
18229}
18230
18231DUK_EXTERNAL void duk_to_null(duk_context *ctx, duk_idx_t idx) {
18232 duk_hthread *thr = (duk_hthread *) ctx;
18233 duk_tval *tv;
18234
18235 DUK_ASSERT_CTX_VALID(ctx);
18236 DUK_UNREF(thr);
18237
18238 tv = duk_require_tval(ctx, idx);
18239 DUK_ASSERT(tv != NULL);
18240 DUK_TVAL_SET_NULL_UPDREF(thr, tv); /* side effects */
18241}
18242
18243/* E5 Section 9.1 */
18244DUK_EXTERNAL void duk_to_primitive(duk_context *ctx, duk_idx_t idx, duk_int_t hint) {
18245 duk_hthread *thr = (duk_hthread *) ctx;
18246 /* inline initializer for coercers[] is not allowed by old compilers like BCC */
18247 duk_small_int_t coercers[2];
18248 duk_small_uint_t class_number;
18249
18250 DUK_ASSERT_CTX_VALID(ctx);
18251 DUK_ASSERT(hint == DUK_HINT_NONE || hint == DUK_HINT_NUMBER || hint == DUK_HINT_STRING);
18252
18253 idx = duk_require_normalize_index(ctx, idx);
18254
18255 if (!duk_check_type_mask(ctx, idx, DUK_TYPE_MASK_OBJECT |
18256 DUK_TYPE_MASK_LIGHTFUNC |
18257 DUK_TYPE_MASK_BUFFER)) {
18258 /* Any other values stay as is. */
18259 DUK_ASSERT(!duk_is_buffer(ctx, idx)); /* duk_to_string() relies on this behavior */
18260 return;
18261 }
18262
18263 class_number = duk_get_class_number(ctx, idx);
18264
18265 /* XXX: Symbol objects normally coerce via the ES2015-revised ToPrimitive()
18266 * algorithm which consults value[@@toPrimitive] and avoids calling
18267 * .valueOf() and .toString(). Before that is implemented, special
18268 * case Symbol objects to behave as if they had the default @@toPrimitive
18269 * algorithm of E6 Section 19.4.3.4, i.e. return the plain symbol value
18270 * with no further side effects.
18271 */
18272
18273 if (class_number == DUK_HOBJECT_CLASS_SYMBOL) {
18274 duk_hobject *h_obj;
18275 duk_hstring *h_str;
18276
18277 /* XXX: pretty awkward, index based API for internal value access? */
18278 h_obj = duk_known_hobject(ctx, idx);
18279 h_str = duk_hobject_get_internal_value_string(thr->heap, h_obj);
18280 if (h_str) {
18281 duk_push_hstring(ctx, h_str);
18282 duk_replace(ctx, idx);
18283 return;
18284 }
18285 }
18286
18287
18288 /* Objects are coerced based on E5 specification.
18289 * Lightfuncs are coerced because they behave like
18290 * objects even if they're internally a primitive
18291 * type. Same applies to plain buffers, which behave
18292 * like ArrayBuffer objects since Duktape 2.x.
18293 */
18294
18295 coercers[0] = DUK_STRIDX_VALUE_OF;
18296 coercers[1] = DUK_STRIDX_TO_STRING;
18297
18298 if (hint == DUK_HINT_NONE) {
18299 if (class_number == DUK_HOBJECT_CLASS_DATE) {
18300 hint = DUK_HINT_STRING;
18301 } else {
18302 hint = DUK_HINT_NUMBER;
18303 }
18304 }
18305
18306 if (hint == DUK_HINT_STRING) {
18307 coercers[0] = DUK_STRIDX_TO_STRING;
18308 coercers[1] = DUK_STRIDX_VALUE_OF;
18309 }
18310
18311 if (duk__defaultvalue_coerce_attempt(ctx, idx, coercers[0])) {
18312 DUK_ASSERT(!duk_is_buffer(ctx, idx)); /* duk_to_string() relies on this behavior */
18313 return;
18314 }
18315
18316 if (duk__defaultvalue_coerce_attempt(ctx, idx, coercers[1])) {
18317 DUK_ASSERT(!duk_is_buffer(ctx, idx)); /* duk_to_string() relies on this behavior */
18318 return;
18319 }
18320
18321 DUK_ERROR_TYPE(thr, DUK_STR_TOPRIMITIVE_FAILED);
18322}
18323
18324/* E5 Section 9.2 */
18325DUK_EXTERNAL duk_bool_t duk_to_boolean(duk_context *ctx, duk_idx_t idx) {
18326 duk_hthread *thr = (duk_hthread *) ctx;
18327 duk_tval *tv;
18328 duk_bool_t val;
18329
18330 DUK_ASSERT_CTX_VALID(ctx);
18331 DUK_UNREF(thr);
18332
18333 idx = duk_require_normalize_index(ctx, idx);
18334 tv = DUK_GET_TVAL_POSIDX(ctx, idx);
18335 DUK_ASSERT(tv != NULL);
18336
18337 val = duk_js_toboolean(tv);
18338 DUK_ASSERT(val == 0 || val == 1);
18339
18340 /* Note: no need to re-lookup tv, conversion is side effect free. */
18341 DUK_ASSERT(tv != NULL);
18342 DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv, val); /* side effects */
18343 return val;
18344}
18345
18346DUK_EXTERNAL duk_double_t duk_to_number(duk_context *ctx, duk_idx_t idx) {
18347 duk_hthread *thr = (duk_hthread *) ctx;
18348 duk_tval *tv;
18349 duk_double_t d;
18350
18351 DUK_ASSERT_CTX_VALID(ctx);
18352
18353 /* XXX: No need to normalize; the whole operation could be inlined here to
18354 * avoid 'tv' re-lookup.
18355 */
18356 idx = duk_require_normalize_index(ctx, idx);
18357 tv = DUK_GET_TVAL_POSIDX(ctx, idx);
18358 DUK_ASSERT(tv != NULL);
18359 d = duk_js_tonumber(thr, tv); /* XXX: fastint coercion? now result will always be a non-fastint */
18360
18361 /* ToNumber() may have side effects so must relookup 'tv'. */
18362 tv = DUK_GET_TVAL_POSIDX(ctx, idx);
18363 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, d); /* side effects */
18364 return d;
18365}
18366
18367DUK_INTERNAL duk_double_t duk_to_number_m1(duk_context *ctx) {
18368 return duk_to_number(ctx, -1);
18369}
18370DUK_INTERNAL duk_double_t duk_to_number_m2(duk_context *ctx) {
18371 return duk_to_number(ctx, -2);
18372}
18373
18374DUK_INTERNAL duk_double_t duk_to_number_tval(duk_context *ctx, duk_tval *tv) {
18375 duk_double_t res;
18376
18377 DUK_ASSERT_CTX_VALID(ctx);
18378
18379 duk_push_tval(ctx, tv);
18380 res = duk_to_number(ctx, -1);
18381 duk_pop(ctx);
18382 return res;
18383}
18384
18385/* XXX: combine all the integer conversions: they share everything
18386 * but the helper function for coercion.
18387 */
18388
18389typedef duk_double_t (*duk__toint_coercer)(duk_hthread *thr, duk_tval *tv);
18390
18391DUK_LOCAL duk_double_t duk__to_int_uint_helper(duk_context *ctx, duk_idx_t idx, duk__toint_coercer coerce_func) {
18392 duk_hthread *thr = (duk_hthread *) ctx;
18393 duk_tval *tv;
18394 duk_double_t d;
18395
18396 DUK_ASSERT_CTX_VALID(ctx);
18397
18398 tv = duk_require_tval(ctx, idx);
18399 DUK_ASSERT(tv != NULL);
18400 d = coerce_func(thr, tv);
18401
18402 /* XXX: fastint? */
18403
18404 /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
18405 tv = duk_require_tval(ctx, idx);
18406 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, d); /* side effects */
18407 return d;
18408}
18409
18410DUK_EXTERNAL duk_int_t duk_to_int(duk_context *ctx, duk_idx_t idx) {
18411 /* Value coercion (in stack): ToInteger(), E5 Section 9.4
18412 * API return value coercion: custom
18413 */
18414 DUK_ASSERT_CTX_VALID(ctx);
18415 (void) duk__to_int_uint_helper(ctx, idx, duk_js_tointeger);
18416 return (duk_int_t) duk__api_coerce_d2i(ctx, idx, 0 /*require*/);
18417}
18418
18419DUK_EXTERNAL duk_uint_t duk_to_uint(duk_context *ctx, duk_idx_t idx) {
18420 /* Value coercion (in stack): ToInteger(), E5 Section 9.4
18421 * API return value coercion: custom
18422 */
18423 DUK_ASSERT_CTX_VALID(ctx);
18424 (void) duk__to_int_uint_helper(ctx, idx, duk_js_tointeger);
18425 return (duk_uint_t) duk__api_coerce_d2ui(ctx, idx, 0 /*require*/);
18426}
18427
18428DUK_EXTERNAL duk_int32_t duk_to_int32(duk_context *ctx, duk_idx_t idx) {
18429 duk_hthread *thr = (duk_hthread *) ctx;
18430 duk_tval *tv;
18431 duk_int32_t ret;
18432
18433 DUK_ASSERT_CTX_VALID(ctx);
18434
18435 tv = duk_require_tval(ctx, idx);
18436 DUK_ASSERT(tv != NULL);
18437 ret = duk_js_toint32(thr, tv);
18438
18439 /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
18440 tv = duk_require_tval(ctx, idx);
18441 DUK_TVAL_SET_I32_UPDREF(thr, tv, ret); /* side effects */
18442 return ret;
18443}
18444
18445DUK_EXTERNAL duk_uint32_t duk_to_uint32(duk_context *ctx, duk_idx_t idx) {
18446 duk_hthread *thr = (duk_hthread *) ctx;
18447 duk_tval *tv;
18448 duk_uint32_t ret;
18449
18450 DUK_ASSERT_CTX_VALID(ctx);
18451
18452 tv = duk_require_tval(ctx, idx);
18453 DUK_ASSERT(tv != NULL);
18454 ret = duk_js_touint32(thr, tv);
18455
18456 /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
18457 tv = duk_require_tval(ctx, idx);
18458 DUK_TVAL_SET_U32_UPDREF(thr, tv, ret); /* side effects */
18459 return ret;
18460}
18461
18462DUK_EXTERNAL duk_uint16_t duk_to_uint16(duk_context *ctx, duk_idx_t idx) {
18463 duk_hthread *thr = (duk_hthread *) ctx;
18464 duk_tval *tv;
18465 duk_uint16_t ret;
18466
18467 DUK_ASSERT_CTX_VALID(ctx);
18468
18469 tv = duk_require_tval(ctx, idx);
18470 DUK_ASSERT(tv != NULL);
18471 ret = duk_js_touint16(thr, tv);
18472
18473 /* Relookup in case coerce_func() has side effects, e.g. ends up coercing an object */
18474 tv = duk_require_tval(ctx, idx);
18475 DUK_TVAL_SET_U32_UPDREF(thr, tv, ret); /* side effects */
18476 return ret;
18477}
18478
18479#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
18480/* Special coercion for Uint8ClampedArray. */
18481DUK_INTERNAL duk_uint8_t duk_to_uint8clamped(duk_context *ctx, duk_idx_t idx) {
18482 duk_double_t d;
18483 duk_double_t t;
18484 duk_uint8_t ret;
18485
18486 /* XXX: Simplify this algorithm, should be possible to come up with
18487 * a shorter and faster algorithm by inspecting IEEE representation
18488 * directly.
18489 */
18490
18491 d = duk_to_number(ctx, idx);
18492 if (d <= 0.0) {
18493 return 0;
18494 } else if (d >= 255) {
18495 return 255;
18496 } else if (DUK_ISNAN(d)) {
18497 /* Avoid NaN-to-integer coercion as it is compiler specific. */
18498 return 0;
18499 }
18500
18501 t = d - DUK_FLOOR(d);
18502 if (t == 0.5) {
18503 /* Exact halfway, round to even. */
18504 ret = (duk_uint8_t) d;
18505 ret = (ret + 1) & 0xfe; /* Example: d=3.5, t=0.5 -> ret = (3 + 1) & 0xfe = 4 & 0xfe = 4
18506 * Example: d=4.5, t=0.5 -> ret = (4 + 1) & 0xfe = 5 & 0xfe = 4
18507 */
18508 } else {
18509 /* Not halfway, round to nearest. */
18510 ret = (duk_uint8_t) (d + 0.5);
18511 }
18512 return ret;
18513}
18514#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
18515
18516DUK_EXTERNAL const char *duk_to_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len) {
18517 DUK_ASSERT_CTX_VALID(ctx);
18518
18519 (void) duk_to_string(ctx, idx);
18520 DUK_ASSERT(duk_is_string(ctx, idx));
18521 return duk_require_lstring(ctx, idx, out_len);
18522}
18523
18524DUK_LOCAL duk_ret_t duk__safe_to_string_raw(duk_context *ctx, void *udata) {
18525 DUK_ASSERT_CTX_VALID(ctx);
18526 DUK_UNREF(udata);
18527
18528 duk_to_string(ctx, -1);
18529 return 1;
18530}
18531
18532DUK_EXTERNAL const char *duk_safe_to_lstring(duk_context *ctx, duk_idx_t idx, duk_size_t *out_len) {
18533 DUK_ASSERT_CTX_VALID(ctx);
18534
18535 idx = duk_require_normalize_index(ctx, idx);
18536
18537 /* We intentionally ignore the duk_safe_call() return value and only
18538 * check the output type. This way we don't also need to check that
18539 * the returned value is indeed a string in the success case.
18540 */
18541
18542 duk_dup(ctx, idx);
18543 (void) duk_safe_call(ctx, duk__safe_to_string_raw, NULL /*udata*/, 1 /*nargs*/, 1 /*nrets*/);
18544 if (!duk_is_string(ctx, -1)) {
18545 /* Error: try coercing error to string once. */
18546 (void) duk_safe_call(ctx, duk__safe_to_string_raw, NULL /*udata*/, 1 /*nargs*/, 1 /*nrets*/);
18547 if (!duk_is_string(ctx, -1)) {
18548 /* Double error */
18549 duk_pop(ctx);
18550 duk_push_hstring_stridx(ctx, DUK_STRIDX_UC_ERROR);
18551 } else {
18552 ;
18553 }
18554 } else {
18555 /* String; may be a symbol, accepted. */
18556 ;
18557 }
18558 DUK_ASSERT(duk_is_string(ctx, -1));
18559
18560 duk_replace(ctx, idx);
18561 DUK_ASSERT(duk_get_string(ctx, idx) != NULL);
18562 return duk_get_lstring(ctx, idx, out_len);
18563}
18564
18565DUK_INTERNAL duk_hstring *duk_to_property_key_hstring(duk_context *ctx, duk_idx_t idx) {
18566 duk_hstring *h;
18567
18568 DUK_ASSERT_CTX_VALID(ctx);
18569
18570 duk_to_primitive(ctx, idx, DUK_HINT_STRING); /* needed for e.g. Symbol objects */
18571 h = duk_get_hstring(ctx, idx);
18572 if (h == NULL) {
18573 /* The "is string?" check may seem unnecessary, but as things
18574 * are duk_to_hstring() invokes ToString() which fails for
18575 * symbols. But since symbols are already strings for Duktape
18576 * C API, we check for that before doing the coercion.
18577 */
18578 h = duk_to_hstring(ctx, idx);
18579 }
18580 DUK_ASSERT(h != NULL);
18581 return h;
18582}
18583
18584#if defined(DUK_USE_DEBUGGER_SUPPORT) /* only needed by debugger for now */
18585DUK_INTERNAL duk_hstring *duk_safe_to_hstring(duk_context *ctx, duk_idx_t idx) {
18586 (void) duk_safe_to_string(ctx, idx);
18587 DUK_ASSERT(duk_is_string(ctx, idx));
18588 DUK_ASSERT(duk_get_hstring(ctx, idx) != NULL);
18589 return duk_known_hstring(ctx, idx);
18590}
18591#endif
18592
18593/* Push Object.prototype.toString() output for 'tv'. */
18594DUK_INTERNAL void duk_push_class_string_tval(duk_context *ctx, duk_tval *tv) {
18595 duk_hthread *thr;
18596 duk_small_uint_t stridx;
18597 duk_hstring *h_strclass;
18598
18599 DUK_ASSERT_CTX_VALID(ctx);
18600 thr = (duk_hthread *) ctx;
18601 DUK_UNREF(thr);
18602
18603 switch (DUK_TVAL_GET_TAG(tv)) {
18604 case DUK_TAG_UNUSED: /* Treat like 'undefined', shouldn't happen. */
18605 case DUK_TAG_UNDEFINED: {
18606 stridx = DUK_STRIDX_UC_UNDEFINED;
18607 break;
18608 }
18609 case DUK_TAG_NULL: {
18610 stridx = DUK_STRIDX_UC_NULL;
18611 break;
18612 }
18613 case DUK_TAG_BOOLEAN: {
18614 stridx = DUK_STRIDX_UC_BOOLEAN;
18615 break;
18616 }
18617 case DUK_TAG_POINTER: {
18618 stridx = DUK_STRIDX_UC_POINTER;
18619 break;
18620 }
18621 case DUK_TAG_LIGHTFUNC: {
18622 stridx = DUK_STRIDX_UC_FUNCTION;
18623 break;
18624 }
18625 case DUK_TAG_STRING: {
18626 duk_hstring *h;
18627 h = DUK_TVAL_GET_STRING(tv);
18628 DUK_ASSERT(h != NULL);
18629 if (DUK_HSTRING_HAS_SYMBOL(h)) {
18630 stridx = DUK_STRIDX_UC_SYMBOL;
18631 } else {
18632 stridx = DUK_STRIDX_UC_STRING;
18633 }
18634 break;
18635 }
18636 case DUK_TAG_OBJECT: {
18637 duk_hobject *h;
18638 duk_small_uint_t classnum;
18639
18640 h = DUK_TVAL_GET_OBJECT(tv);
18641 DUK_ASSERT(h != NULL);
18642 classnum = DUK_HOBJECT_GET_CLASS_NUMBER(h);
18643 stridx = DUK_HOBJECT_CLASS_NUMBER_TO_STRIDX(classnum);
18644
18645 /* XXX: This is not entirely correct anymore; in ES2015 the
18646 * default lookup should use @@toStringTag to come up with
18647 * e.g. [object Symbol], [object Uint8Array], etc. See
18648 * ES2015 Section 19.1.3.6. The downside of implementing that
18649 * directly is that the @@toStringTag lookup may have side
18650 * effects, so all call sites must be checked for that.
18651 * Some may need a side-effect free lookup, e.g. avoiding
18652 * getters which are not typical.
18653 */
18654 break;
18655 }
18656 case DUK_TAG_BUFFER: {
18657 stridx = DUK_STRIDX_UINT8_ARRAY;
18658 break;
18659 }
18660#if defined(DUK_USE_FASTINT)
18661 case DUK_TAG_FASTINT:
18662 /* Fall through to generic number case. */
18663#endif
18664 default: {
18665 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); /* number (maybe fastint) */
18666 stridx = DUK_STRIDX_UC_NUMBER;
18667 break;
18668 }
18669 }
18670 h_strclass = DUK_HTHREAD_GET_STRING(thr, stridx);
18671 DUK_ASSERT(h_strclass != NULL);
18672
18673 duk_push_sprintf(ctx, "[object %s]", (const char *) DUK_HSTRING_GET_DATA(h_strclass));
18674}
18675
18676/* XXX: other variants like uint, u32 etc */
18677DUK_INTERNAL duk_int_t duk_to_int_clamped_raw(duk_context *ctx, duk_idx_t idx, duk_int_t minval, duk_int_t maxval, duk_bool_t *out_clamped) {
18678 duk_hthread *thr = (duk_hthread *) ctx;
18679 duk_tval *tv;
18680 duk_tval tv_tmp;
18681 duk_double_t d, dmin, dmax;
18682 duk_int_t res;
18683 duk_bool_t clamped = 0;
18684
18685 DUK_ASSERT_CTX_VALID(ctx);
18686
18687 tv = duk_require_tval(ctx, idx);
18688 DUK_ASSERT(tv != NULL);
18689 d = duk_js_tointeger(thr, tv); /* E5 Section 9.4, ToInteger() */
18690
18691 dmin = (duk_double_t) minval;
18692 dmax = (duk_double_t) maxval;
18693
18694 if (d < dmin) {
18695 clamped = 1;
18696 res = minval;
18697 d = dmin;
18698 } else if (d > dmax) {
18699 clamped = 1;
18700 res = maxval;
18701 d = dmax;
18702 } else {
18703 res = (duk_int_t) d;
18704 }
18705 DUK_UNREF(d); /* SCANBUILD: with suitable dmin/dmax limits 'd' is unused */
18706 /* 'd' and 'res' agree here */
18707
18708 /* Relookup in case duk_js_tointeger() ends up e.g. coercing an object. */
18709 tv = duk_get_tval(ctx, idx);
18710 DUK_ASSERT(tv != NULL); /* not popped by side effect */
18711 DUK_TVAL_SET_TVAL(&tv_tmp, tv);
18712#if defined(DUK_USE_FASTINT)
18713#if (DUK_INT_MAX <= 0x7fffffffL)
18714 DUK_TVAL_SET_I32(tv, res);
18715#else
18716 /* Clamping needed if duk_int_t is 64 bits. */
18717 if (res >= DUK_FASTINT_MIN && res <= DUK_FASTINT_MAX) {
18718 DUK_TVAL_SET_FASTINT(tv, res);
18719 } else {
18720 DUK_TVAL_SET_NUMBER(tv, d);
18721 }
18722#endif
18723#else
18724 DUK_TVAL_SET_NUMBER(tv, d); /* no need to incref */
18725#endif
18726 DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
18727
18728 if (out_clamped) {
18729 *out_clamped = clamped;
18730 } else {
18731 /* coerced value is updated to value stack even when RangeError thrown */
18732 if (clamped) {
18733 DUK_ERROR_RANGE(thr, DUK_STR_NUMBER_OUTSIDE_RANGE);
18734 }
18735 }
18736
18737 return res;
18738}
18739
18740DUK_INTERNAL duk_int_t duk_to_int_clamped(duk_context *ctx, duk_idx_t idx, duk_idx_t minval, duk_idx_t maxval) {
18741 duk_bool_t dummy;
18742 return duk_to_int_clamped_raw(ctx, idx, minval, maxval, &dummy);
18743}
18744
18745DUK_INTERNAL duk_int_t duk_to_int_check_range(duk_context *ctx, duk_idx_t idx, duk_int_t minval, duk_int_t maxval) {
18746 return duk_to_int_clamped_raw(ctx, idx, minval, maxval, NULL); /* out_clamped==NULL -> RangeError if outside range */
18747}
18748
18749DUK_EXTERNAL const char *duk_to_string(duk_context *ctx, duk_idx_t idx) {
18750 duk_hthread *thr = (duk_hthread *) ctx;
18751 duk_tval *tv;
18752
18753 DUK_ASSERT_CTX_VALID(ctx);
18754 DUK_UNREF(thr);
18755
18756 idx = duk_require_normalize_index(ctx, idx);
18757 tv = DUK_GET_TVAL_POSIDX(ctx, idx);
18758 DUK_ASSERT(tv != NULL);
18759
18760 switch (DUK_TVAL_GET_TAG(tv)) {
18761 case DUK_TAG_UNDEFINED: {
18762 duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_UNDEFINED);
18763 break;
18764 }
18765 case DUK_TAG_NULL: {
18766 duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_NULL);
18767 break;
18768 }
18769 case DUK_TAG_BOOLEAN: {
18770 if (DUK_TVAL_GET_BOOLEAN(tv)) {
18771 duk_push_hstring_stridx(ctx, DUK_STRIDX_TRUE);
18772 } else {
18773 duk_push_hstring_stridx(ctx, DUK_STRIDX_FALSE);
18774 }
18775 break;
18776 }
18777 case DUK_TAG_STRING: {
18778 /* Nop for actual strings, TypeError for Symbols.
18779 * Because various internals rely on ToString() coercion of
18780 * internal strings, -allow- (NOP) string coercion for hidden
18781 * symbols.
18782 */
18783#if 1
18784 duk_hstring *h;
18785 h = DUK_TVAL_GET_STRING(tv);
18786 DUK_ASSERT(h != NULL);
18787 if (DUK_HSTRING_HAS_SYMBOL(h)) {
18788 DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_CANNOT_STRING_COERCE_SYMBOL);
18789 } else {
18790 goto skip_replace;
18791 }
18792#else
18793 goto skip_replace;
18794#endif
18795 }
18796 case DUK_TAG_BUFFER: /* Go through Uint8Array.prototype.toString() for coercion. */
18797 case DUK_TAG_OBJECT: {
18798 /* Plain buffers: go through ArrayBuffer.prototype.toString()
18799 * for coercion.
18800 *
18801 * Symbol objects: duk_to_primitive() results in a plain symbol
18802 * value, and duk_to_string() then causes a TypeError.
18803 */
18804 duk_to_primitive(ctx, idx, DUK_HINT_STRING);
18805 DUK_ASSERT(!duk_is_buffer(ctx, idx)); /* ToPrimitive() must guarantee */
18806 DUK_ASSERT(!duk_is_object(ctx, idx));
18807 return duk_to_string(ctx, idx); /* Note: recursive call */
18808 }
18809 case DUK_TAG_POINTER: {
18810 void *ptr = DUK_TVAL_GET_POINTER(tv);
18811 if (ptr != NULL) {
18812 duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) ptr);
18813 } else {
18814 /* Represent a null pointer as 'null' to be consistent with
18815 * the JX format variant. Native '%p' format for a NULL
18816 * pointer may be e.g. '(nil)'.
18817 */
18818 duk_push_hstring_stridx(ctx, DUK_STRIDX_LC_NULL);
18819 }
18820 break;
18821 }
18822 case DUK_TAG_LIGHTFUNC: {
18823 /* Should match Function.prototype.toString() */
18824 duk_push_lightfunc_tostring(ctx, tv);
18825 break;
18826 }
18827#if defined(DUK_USE_FASTINT)
18828 case DUK_TAG_FASTINT:
18829#endif
18830 default: {
18831 /* number */
18832 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
18833 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
18834 duk_push_tval(ctx, tv);
18835 duk_numconv_stringify(ctx,
18836 10 /*radix*/,
18837 0 /*precision:shortest*/,
18838 0 /*force_exponential*/);
18839 break;
18840 }
18841 }
18842
18843 duk_replace(ctx, idx);
18844
18845 skip_replace:
18846 DUK_ASSERT(duk_is_string(ctx, idx));
18847 return duk_require_string(ctx, idx);
18848}
18849
18850DUK_INTERNAL duk_hstring *duk_to_hstring(duk_context *ctx, duk_idx_t idx) {
18851 duk_hstring *ret;
18852 DUK_ASSERT_CTX_VALID(ctx);
18853 duk_to_string(ctx, idx);
18854 ret = duk_get_hstring(ctx, idx);
18855 DUK_ASSERT(ret != NULL);
18856 return ret;
18857}
18858
18859DUK_INTERNAL duk_hstring *duk_to_hstring_m1(duk_context *ctx) {
18860 return duk_to_hstring(ctx, -1);
18861}
18862
18863DUK_INTERNAL duk_hstring *duk_to_hstring_acceptsymbol(duk_context *ctx, duk_idx_t idx) {
18864 duk_hstring *ret;
18865 DUK_ASSERT_CTX_VALID(ctx);
18866 ret = duk_get_hstring(ctx, idx);
18867 if (ret && DUK_HSTRING_HAS_SYMBOL(ret)) {
18868 return ret;
18869 }
18870 return duk_to_hstring(ctx, idx);
18871}
18872
18873/* Convert a plain buffer or any buffer object into a string, using the buffer
18874 * bytes 1:1 in the internal string representation. For views the active byte
18875 * slice (not element slice interpreted as an initializer) is used. This is
18876 * necessary in Duktape 2.x because ToString(plainBuffer) no longer creates a
18877 * string with the same bytes as in the buffer but rather (usually)
18878 * '[object ArrayBuffer]'.
18879 */
18880DUK_EXTERNAL const char *duk_buffer_to_string(duk_context *ctx, duk_idx_t idx) {
18881 void *ptr_src;
18882 duk_size_t len;
18883 const char *res;
18884
18885 idx = duk_require_normalize_index(ctx, idx);
18886
18887 ptr_src = duk_require_buffer_data(ctx, idx, &len);
18888 DUK_ASSERT(ptr_src != NULL || len == 0);
18889
18890 res = duk_push_lstring(ctx, (const char *) ptr_src, len);
18891 duk_replace(ctx, idx);
18892 return res;
18893}
18894
18895DUK_EXTERNAL void *duk_to_buffer_raw(duk_context *ctx, duk_idx_t idx, duk_size_t *out_size, duk_uint_t mode) {
18896 duk_hthread *thr = (duk_hthread *) ctx;
18897 duk_hbuffer *h_buf;
18898 const duk_uint8_t *src_data;
18899 duk_size_t src_size;
18900 duk_uint8_t *dst_data;
18901
18902 DUK_ASSERT_CTX_VALID(ctx);
18903 DUK_UNREF(thr);
18904
18905 idx = duk_require_normalize_index(ctx, idx);
18906
18907 h_buf = duk_get_hbuffer(ctx, idx);
18908 if (h_buf != NULL) {
18909 /* Buffer is kept as is, with the fixed/dynamic nature of the
18910 * buffer only changed if requested. An external buffer
18911 * is converted into a non-external dynamic buffer in a
18912 * duk_to_dynamic_buffer() call.
18913 */
18914 duk_uint_t tmp;
18915 duk_uint8_t *tmp_ptr;
18916
18917 tmp_ptr = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_buf);
18918 src_data = (const duk_uint8_t *) tmp_ptr;
18919 src_size = DUK_HBUFFER_GET_SIZE(h_buf);
18920
18921 tmp = (DUK_HBUFFER_HAS_DYNAMIC(h_buf) ? DUK_BUF_MODE_DYNAMIC : DUK_BUF_MODE_FIXED);
18922 if ((tmp == mode && !DUK_HBUFFER_HAS_EXTERNAL(h_buf)) ||
18923 mode == DUK_BUF_MODE_DONTCARE) {
18924 /* Note: src_data may be NULL if input is a zero-size
18925 * dynamic buffer.
18926 */
18927 dst_data = tmp_ptr;
18928 goto skip_copy;
18929 }
18930 } else {
18931 /* Non-buffer value is first ToString() coerced, then converted
18932 * to a buffer (fixed buffer is used unless a dynamic buffer is
18933 * explicitly requested). Symbols are rejected with a TypeError.
18934 * XXX: C API could maybe allow symbol-to-buffer coercion?
18935 */
18936 src_data = (const duk_uint8_t *) duk_to_lstring(ctx, idx, &src_size);
18937 }
18938
18939 dst_data = (duk_uint8_t *) duk_push_buffer(ctx, src_size, (mode == DUK_BUF_MODE_DYNAMIC) /*dynamic*/);
18940 if (DUK_LIKELY(src_size > 0)) {
18941 /* When src_size == 0, src_data may be NULL (if source
18942 * buffer is dynamic), and dst_data may be NULL (if
18943 * target buffer is dynamic). Avoid zero-size memcpy()
18944 * with an invalid pointer.
18945 */
18946 DUK_MEMCPY((void *) dst_data, (const void *) src_data, (size_t) src_size);
18947 }
18948 duk_replace(ctx, idx);
18949 skip_copy:
18950
18951 if (out_size) {
18952 *out_size = src_size;
18953 }
18954 return dst_data;
18955}
18956
18957DUK_EXTERNAL void *duk_to_pointer(duk_context *ctx, duk_idx_t idx) {
18958 duk_tval *tv;
18959 void *res;
18960
18961 DUK_ASSERT_CTX_VALID(ctx);
18962
18963 idx = duk_require_normalize_index(ctx, idx);
18964 tv = DUK_GET_TVAL_POSIDX(ctx, idx);
18965 DUK_ASSERT(tv != NULL);
18966
18967 switch (DUK_TVAL_GET_TAG(tv)) {
18968 case DUK_TAG_UNDEFINED:
18969 case DUK_TAG_NULL:
18970 case DUK_TAG_BOOLEAN:
18971 res = NULL;
18972 break;
18973 case DUK_TAG_POINTER:
18974 res = DUK_TVAL_GET_POINTER(tv);
18975 break;
18976 case DUK_TAG_STRING:
18977 case DUK_TAG_OBJECT:
18978 case DUK_TAG_BUFFER:
18979 /* Heap allocated: return heap pointer which is NOT useful
18980 * for the caller, except for debugging.
18981 */
18982 res = (void *) DUK_TVAL_GET_HEAPHDR(tv);
18983 break;
18984 case DUK_TAG_LIGHTFUNC:
18985 /* Function pointers do not always cast correctly to void *
18986 * (depends on memory and segmentation model for instance),
18987 * so they coerce to NULL.
18988 */
18989 res = NULL;
18990 break;
18991#if defined(DUK_USE_FASTINT)
18992 case DUK_TAG_FASTINT:
18993#endif
18994 default:
18995 /* number */
18996 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
18997 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
18998 res = NULL;
18999 break;
19000 }
19001
19002 duk_push_pointer(ctx, res);
19003 duk_replace(ctx, idx);
19004 return res;
19005}
19006
19007DUK_LOCAL void duk__push_func_from_lightfunc(duk_context *ctx, duk_c_function func, duk_small_uint_t lf_flags) {
19008 duk_idx_t nargs;
19009 duk_uint_t flags = 0; /* shared flags for a subset of types */
19010 duk_small_uint_t lf_len;
19011 duk_hnatfunc *nf;
19012
19013 nargs = (duk_idx_t) DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
19014 if (nargs == DUK_LFUNC_NARGS_VARARGS) {
19015 nargs = (duk_idx_t) DUK_VARARGS;
19016 }
19017
19018 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
19019 DUK_HOBJECT_FLAG_CONSTRUCTABLE |
19020 DUK_HOBJECT_FLAG_NATFUNC |
19021 DUK_HOBJECT_FLAG_NEWENV |
19022 DUK_HOBJECT_FLAG_STRICT |
19023 DUK_HOBJECT_FLAG_NOTAIL |
19024 /* DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC: omitted here intentionally */
19025 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
19026 (void) duk__push_c_function_raw(ctx, func, nargs, flags);
19027
19028 lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
19029 if ((duk_idx_t) lf_len != nargs) {
19030 /* Explicit length is only needed if it differs from 'nargs'. */
19031 duk_push_int(ctx, (duk_int_t) lf_len);
19032 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_NONE);
19033 }
19034
19035#if defined(DUK_USE_FUNC_NAME_PROPERTY)
19036 duk_push_lightfunc_name_raw(ctx, func, lf_flags);
19037 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
19038#endif
19039
19040 nf = duk_known_hnatfunc(ctx, -1);
19041 nf->magic = (duk_int16_t) DUK_LFUNC_FLAGS_GET_MAGIC(lf_flags);
19042
19043 /* Enable DUKFUNC exotic behavior once properties are set up. */
19044 DUK_HOBJECT_SET_EXOTIC_DUKFUNC((duk_hobject *) nf);
19045}
19046
19047DUK_EXTERNAL void duk_to_object(duk_context *ctx, duk_idx_t idx) {
19048 duk_hthread *thr = (duk_hthread *) ctx;
19049 duk_tval *tv;
19050 duk_uint_t flags = 0; /* shared flags for a subset of types */
19051 duk_small_int_t proto = 0;
19052
19053 DUK_ASSERT_CTX_VALID(ctx);
19054
19055 idx = duk_require_normalize_index(ctx, idx);
19056 tv = DUK_GET_TVAL_POSIDX(ctx, idx);
19057 DUK_ASSERT(tv != NULL);
19058
19059 switch (DUK_TVAL_GET_TAG(tv)) {
19060#if !defined(DUK_USE_BUFFEROBJECT_SUPPORT)
19061 case DUK_TAG_BUFFER: /* With no bufferobject support, don't object coerce. */
19062#endif
19063 case DUK_TAG_UNDEFINED:
19064 case DUK_TAG_NULL: {
19065 DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE);
19066 break;
19067 }
19068 case DUK_TAG_BOOLEAN: {
19069 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
19070 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_BOOLEAN);
19071 proto = DUK_BIDX_BOOLEAN_PROTOTYPE;
19072 goto create_object;
19073 }
19074 case DUK_TAG_STRING: {
19075 duk_hstring *h;
19076 h = DUK_TVAL_GET_STRING(tv);
19077 DUK_ASSERT(h != NULL);
19078 if (DUK_HSTRING_HAS_SYMBOL(h)) {
19079 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
19080 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_SYMBOL);
19081 proto = DUK_BIDX_SYMBOL_PROTOTYPE;
19082 } else {
19083 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
19084 DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ |
19085 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING);
19086 proto = DUK_BIDX_STRING_PROTOTYPE;
19087 }
19088 goto create_object;
19089 }
19090 case DUK_TAG_OBJECT: {
19091 /* nop */
19092 break;
19093 }
19094#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
19095 case DUK_TAG_BUFFER: {
19096 /* A plain buffer object coerces to a full ArrayBuffer which
19097 * is not fully transparent behavior (ToObject() should be a
19098 * nop for an object). This behavior matches lightfuncs which
19099 * also coerce to an equivalent Function object. There are
19100 * also downsides to defining ToObject(plainBuffer) as a no-op;
19101 * for example duk_to_hobject() could result in a NULL pointer.
19102 */
19103 duk_hbuffer *h_buf;
19104
19105 h_buf = DUK_TVAL_GET_BUFFER(tv);
19106 DUK_ASSERT(h_buf != NULL);
19107 duk_hbufobj_push_uint8array_from_plain(thr, h_buf);
19108 goto replace_value;
19109 }
19110#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
19111 case DUK_TAG_POINTER: {
19112 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
19113 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER);
19114 proto = DUK_BIDX_POINTER_PROTOTYPE;
19115 goto create_object;
19116 }
19117 case DUK_TAG_LIGHTFUNC: {
19118 /* Lightfunc coerces to a Function instance with concrete
19119 * properties. Since 'length' is virtual for Duktape/C
19120 * functions, don't need to define that. The result is made
19121 * extensible to mimic what happens to strings in object
19122 * coercion:
19123 *
19124 * > Object.isExtensible(Object('foo'))
19125 * true
19126 */
19127 duk_small_uint_t lf_flags;
19128 duk_c_function func;
19129
19130 DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags);
19131 duk__push_func_from_lightfunc(ctx, func, lf_flags);
19132 goto replace_value;
19133 }
19134#if defined(DUK_USE_FASTINT)
19135 case DUK_TAG_FASTINT:
19136#endif
19137 default: {
19138 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
19139 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
19140 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
19141 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_NUMBER);
19142 proto = DUK_BIDX_NUMBER_PROTOTYPE;
19143 goto create_object;
19144 }
19145 }
19146 DUK_ASSERT(duk_is_object(ctx, idx));
19147 return;
19148
19149 create_object:
19150 (void) duk_push_object_helper(ctx, flags, proto);
19151
19152 /* Note: Boolean prototype's internal value property is not writable,
19153 * but duk_xdef_prop_stridx() disregards the write protection. Boolean
19154 * instances are immutable.
19155 *
19156 * String and buffer special behaviors are already enabled which is not
19157 * ideal, but a write to the internal value is not affected by them.
19158 */
19159 duk_dup(ctx, idx);
19160 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
19161
19162 replace_value:
19163 duk_replace(ctx, idx);
19164 DUK_ASSERT(duk_is_object(ctx, idx));
19165}
19166
19167DUK_INTERNAL duk_hobject *duk_to_hobject(duk_context *ctx, duk_idx_t idx) {
19168 duk_hobject *ret;
19169 DUK_ASSERT_CTX_VALID(ctx);
19170 duk_to_object(ctx, idx);
19171 ret = duk_known_hobject(ctx, idx);
19172 return ret;
19173}
19174
19175/*
19176 * Type checking
19177 */
19178
19179DUK_LOCAL duk_bool_t duk__tag_check(duk_context *ctx, duk_idx_t idx, duk_small_uint_t tag) {
19180 duk_tval *tv;
19181
19182 tv = duk_get_tval_or_unused(ctx, idx);
19183 DUK_ASSERT(tv != NULL);
19184 return (DUK_TVAL_GET_TAG(tv) == tag);
19185}
19186
19187DUK_LOCAL duk_bool_t duk__obj_flag_any_default_false(duk_context *ctx, duk_idx_t idx, duk_uint_t flag_mask) {
19188 duk_hobject *obj;
19189
19190 DUK_ASSERT_CTX_VALID(ctx);
19191
19192 obj = duk_get_hobject(ctx, idx);
19193 if (obj) {
19194 return (DUK_HEAPHDR_CHECK_FLAG_BITS((duk_heaphdr *) obj, flag_mask) ? 1 : 0);
19195 }
19196 return 0;
19197}
19198
19199DUK_INTERNAL duk_int_t duk_get_type_tval(duk_tval *tv) {
19200 DUK_ASSERT(tv != NULL);
19201
19202#if defined(DUK_USE_PACKED_TVAL)
19203 switch (DUK_TVAL_GET_TAG(tv)) {
19204 case DUK_TAG_UNUSED:
19205 return DUK_TYPE_NONE;
19206 case DUK_TAG_UNDEFINED:
19207 return DUK_TYPE_UNDEFINED;
19208 case DUK_TAG_NULL:
19209 return DUK_TYPE_NULL;
19210 case DUK_TAG_BOOLEAN:
19211 return DUK_TYPE_BOOLEAN;
19212 case DUK_TAG_STRING:
19213 return DUK_TYPE_STRING;
19214 case DUK_TAG_OBJECT:
19215 return DUK_TYPE_OBJECT;
19216 case DUK_TAG_BUFFER:
19217 return DUK_TYPE_BUFFER;
19218 case DUK_TAG_POINTER:
19219 return DUK_TYPE_POINTER;
19220 case DUK_TAG_LIGHTFUNC:
19221 return DUK_TYPE_LIGHTFUNC;
19222#if defined(DUK_USE_FASTINT)
19223 case DUK_TAG_FASTINT:
19224#endif
19225 default:
19226 /* Note: number has no explicit tag (in 8-byte representation) */
19227 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
19228 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
19229 return DUK_TYPE_NUMBER;
19230 }
19231#else /* DUK_USE_PACKED_TVAL */
19232 DUK_ASSERT(DUK_TVAL_IS_VALID_TAG(tv));
19233 DUK_ASSERT(sizeof(duk__type_from_tag) / sizeof(duk_uint_t) == DUK_TAG_MAX - DUK_TAG_MIN + 1);
19234 return (duk_int_t) duk__type_from_tag[DUK_TVAL_GET_TAG(tv) - DUK_TAG_MIN];
19235#endif /* DUK_USE_PACKED_TVAL */
19236}
19237
19238DUK_EXTERNAL duk_int_t duk_get_type(duk_context *ctx, duk_idx_t idx) {
19239 duk_tval *tv;
19240
19241 DUK_ASSERT_CTX_VALID(ctx);
19242
19243 tv = duk_get_tval_or_unused(ctx, idx);
19244 DUK_ASSERT(tv != NULL);
19245
19246 return duk_get_type_tval(tv);
19247}
19248
19249#if defined(DUK_USE_VERBOSE_ERRORS) && defined(DUK_USE_PARANOID_ERRORS)
19250DUK_LOCAL const char *duk__type_names[] = {
19251 "none",
19252 "undefined",
19253 "null",
19254 "boolean",
19255 "number",
19256 "string",
19257 "object",
19258 "buffer",
19259 "pointer",
19260 "lightfunc"
19261};
19262
19263DUK_INTERNAL const char *duk_get_type_name(duk_context *ctx, duk_idx_t idx) {
19264 duk_int_t type_tag;
19265
19266 type_tag = duk_get_type(ctx, idx);
19267 DUK_ASSERT(type_tag >= DUK_TYPE_MIN && type_tag <= DUK_TYPE_MAX);
19268 DUK_ASSERT(DUK_TYPE_MIN == 0 && sizeof(duk__type_names) / sizeof(const char *) == DUK_TYPE_MAX + 1);
19269
19270 return duk__type_names[type_tag];
19271}
19272#endif
19273
19274DUK_INTERNAL duk_small_uint_t duk_get_class_number(duk_context *ctx, duk_idx_t idx) {
19275 duk_tval *tv;
19276 duk_hobject *obj;
19277
19278 tv = duk_get_tval_or_unused(ctx, idx);
19279 DUK_ASSERT(tv != NULL);
19280
19281 switch (DUK_TVAL_GET_TAG(tv)) {
19282 case DUK_TAG_OBJECT:
19283 obj = DUK_TVAL_GET_OBJECT(tv);
19284 DUK_ASSERT(obj != NULL);
19285 return DUK_HOBJECT_GET_CLASS_NUMBER(obj);
19286 case DUK_TAG_BUFFER:
19287 /* Buffers behave like Uint8Array objects. */
19288 return DUK_HOBJECT_CLASS_UINT8ARRAY;
19289 case DUK_TAG_LIGHTFUNC:
19290 /* Lightfuncs behave like Function objects. */
19291 return DUK_HOBJECT_CLASS_FUNCTION;
19292 default:
19293 /* Primitive or UNUSED, no class number. */
19294 return DUK_HOBJECT_CLASS_NONE;
19295 }
19296}
19297
19298DUK_EXTERNAL duk_bool_t duk_check_type(duk_context *ctx, duk_idx_t idx, duk_int_t type) {
19299 DUK_ASSERT_CTX_VALID(ctx);
19300
19301 return (duk_get_type(ctx, idx) == type) ? 1 : 0;
19302}
19303
19304DUK_INTERNAL duk_uint_t duk_get_type_mask_tval(duk_tval *tv) {
19305 DUK_ASSERT(tv != NULL);
19306
19307#if defined(DUK_USE_PACKED_TVAL)
19308 switch (DUK_TVAL_GET_TAG(tv)) {
19309 case DUK_TAG_UNUSED:
19310 return DUK_TYPE_MASK_NONE;
19311 case DUK_TAG_UNDEFINED:
19312 return DUK_TYPE_MASK_UNDEFINED;
19313 case DUK_TAG_NULL:
19314 return DUK_TYPE_MASK_NULL;
19315 case DUK_TAG_BOOLEAN:
19316 return DUK_TYPE_MASK_BOOLEAN;
19317 case DUK_TAG_STRING:
19318 return DUK_TYPE_MASK_STRING;
19319 case DUK_TAG_OBJECT:
19320 return DUK_TYPE_MASK_OBJECT;
19321 case DUK_TAG_BUFFER:
19322 return DUK_TYPE_MASK_BUFFER;
19323 case DUK_TAG_POINTER:
19324 return DUK_TYPE_MASK_POINTER;
19325 case DUK_TAG_LIGHTFUNC:
19326 return DUK_TYPE_MASK_LIGHTFUNC;
19327#if defined(DUK_USE_FASTINT)
19328 case DUK_TAG_FASTINT:
19329#endif
19330 default:
19331 /* Note: number has no explicit tag (in 8-byte representation) */
19332 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
19333 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
19334 return DUK_TYPE_MASK_NUMBER;
19335 }
19336#else /* DUK_USE_PACKED_TVAL */
19337 DUK_ASSERT(DUK_TVAL_IS_VALID_TAG(tv));
19338 DUK_ASSERT(sizeof(duk__type_mask_from_tag) / sizeof(duk_uint_t) == DUK_TAG_MAX - DUK_TAG_MIN + 1);
19339 return (duk_int_t) duk__type_mask_from_tag[DUK_TVAL_GET_TAG(tv) - DUK_TAG_MIN];
19340#endif /* DUK_USE_PACKED_TVAL */
19341}
19342
19343DUK_EXTERNAL duk_uint_t duk_get_type_mask(duk_context *ctx, duk_idx_t idx) {
19344 duk_tval *tv;
19345
19346 DUK_ASSERT_CTX_VALID(ctx);
19347
19348 tv = duk_get_tval_or_unused(ctx, idx);
19349 DUK_ASSERT(tv != NULL);
19350
19351 return duk_get_type_mask_tval(tv);
19352}
19353
19354DUK_EXTERNAL duk_bool_t duk_check_type_mask(duk_context *ctx, duk_idx_t idx, duk_uint_t mask) {
19355 duk_hthread *thr = (duk_hthread *) ctx;
19356
19357 DUK_ASSERT_CTX_VALID(ctx);
19358
19359 if (duk_get_type_mask(ctx, idx) & mask) {
19360 return 1;
19361 }
19362 if (mask & DUK_TYPE_MASK_THROW) {
19363 DUK_ERROR_TYPE(thr, DUK_STR_UNEXPECTED_TYPE);
19364 DUK_UNREACHABLE();
19365 }
19366 return 0;
19367}
19368
19369DUK_EXTERNAL duk_bool_t duk_is_undefined(duk_context *ctx, duk_idx_t idx) {
19370 DUK_ASSERT_CTX_VALID(ctx);
19371 return duk__tag_check(ctx, idx, DUK_TAG_UNDEFINED);
19372}
19373
19374DUK_EXTERNAL duk_bool_t duk_is_null(duk_context *ctx, duk_idx_t idx) {
19375 DUK_ASSERT_CTX_VALID(ctx);
19376 return duk__tag_check(ctx, idx, DUK_TAG_NULL);
19377}
19378
19379DUK_EXTERNAL duk_bool_t duk_is_boolean(duk_context *ctx, duk_idx_t idx) {
19380 DUK_ASSERT_CTX_VALID(ctx);
19381 return duk__tag_check(ctx, idx, DUK_TAG_BOOLEAN);
19382}
19383
19384DUK_EXTERNAL duk_bool_t duk_is_number(duk_context *ctx, duk_idx_t idx) {
19385 duk_tval *tv;
19386
19387 DUK_ASSERT_CTX_VALID(ctx);
19388
19389 /*
19390 * Number is special because it doesn't have a specific
19391 * tag in the 8-byte representation.
19392 */
19393
19394 /* XXX: shorter version for unpacked representation? */
19395
19396 tv = duk_get_tval_or_unused(ctx, idx);
19397 DUK_ASSERT(tv != NULL);
19398 return DUK_TVAL_IS_NUMBER(tv);
19399}
19400
19401DUK_EXTERNAL duk_bool_t duk_is_nan(duk_context *ctx, duk_idx_t idx) {
19402 /* XXX: This will now return false for non-numbers, even though they would
19403 * coerce to NaN (as a general rule). In particular, duk_get_number()
19404 * returns a NaN for non-numbers, so should this function also return
19405 * true for non-numbers?
19406 */
19407
19408 duk_tval *tv;
19409
19410 DUK_ASSERT_CTX_VALID(ctx);
19411
19412 tv = duk_get_tval_or_unused(ctx, idx);
19413 DUK_ASSERT(tv != NULL);
19414
19415 /* XXX: for packed duk_tval an explicit "is number" check is unnecessary */
19416 if (!DUK_TVAL_IS_NUMBER(tv)) {
19417 return 0;
19418 }
19419 return DUK_ISNAN(DUK_TVAL_GET_NUMBER(tv));
19420}
19421
19422DUK_EXTERNAL duk_bool_t duk_is_string(duk_context *ctx, duk_idx_t idx) {
19423 DUK_ASSERT_CTX_VALID(ctx);
19424 return duk__tag_check(ctx, idx, DUK_TAG_STRING);
19425}
19426
19427DUK_INTERNAL duk_bool_t duk_is_string_notsymbol(duk_context *ctx, duk_idx_t idx) {
19428 DUK_ASSERT_CTX_VALID(ctx);
19429 return duk_get_hstring_notsymbol(ctx, idx) != NULL;
19430}
19431
19432DUK_EXTERNAL duk_bool_t duk_is_object(duk_context *ctx, duk_idx_t idx) {
19433 DUK_ASSERT_CTX_VALID(ctx);
19434 return duk__tag_check(ctx, idx, DUK_TAG_OBJECT);
19435}
19436
19437DUK_EXTERNAL duk_bool_t duk_is_buffer(duk_context *ctx, duk_idx_t idx) {
19438 DUK_ASSERT_CTX_VALID(ctx);
19439 return duk__tag_check(ctx, idx, DUK_TAG_BUFFER);
19440}
19441
19442#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
19443DUK_EXTERNAL duk_bool_t duk_is_buffer_data(duk_context *ctx, duk_idx_t idx) {
19444 duk_tval *tv;
19445
19446 DUK_ASSERT_CTX_VALID(ctx);
19447
19448 tv = duk_get_tval_or_unused(ctx, idx);
19449 DUK_ASSERT(tv != NULL);
19450 if (DUK_TVAL_IS_BUFFER(tv)) {
19451 return 1;
19452 } else if (DUK_TVAL_IS_OBJECT(tv)) {
19453 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
19454 DUK_ASSERT(h != NULL);
19455 if (DUK_HOBJECT_IS_BUFOBJ(h)) {
19456 return 1;
19457 }
19458 }
19459 return 0;
19460}
19461#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
19462DUK_EXTERNAL duk_bool_t duk_is_buffer_data(duk_context *ctx, duk_idx_t idx) {
19463 DUK_ASSERT_CTX_VALID(ctx);
19464
19465 return duk_is_buffer(ctx, idx);
19466}
19467
19468#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
19469
19470DUK_EXTERNAL duk_bool_t duk_is_pointer(duk_context *ctx, duk_idx_t idx) {
19471 DUK_ASSERT_CTX_VALID(ctx);
19472 return duk__tag_check(ctx, idx, DUK_TAG_POINTER);
19473}
19474
19475DUK_EXTERNAL duk_bool_t duk_is_lightfunc(duk_context *ctx, duk_idx_t idx) {
19476 DUK_ASSERT_CTX_VALID(ctx);
19477 return duk__tag_check(ctx, idx, DUK_TAG_LIGHTFUNC);
19478}
19479
19480DUK_EXTERNAL duk_bool_t duk_is_symbol(duk_context *ctx, duk_idx_t idx) {
19481 duk_hstring *h;
19482
19483 DUK_ASSERT_CTX_VALID(ctx);
19484 h = duk_get_hstring(ctx, idx);
19485 if (h != NULL && DUK_HSTRING_HAS_SYMBOL(h)) {
19486 return 1;
19487 }
19488 return 0;
19489}
19490
19491DUK_EXTERNAL duk_bool_t duk_is_array(duk_context *ctx, duk_idx_t idx) {
19492 duk_hobject *obj;
19493
19494 DUK_ASSERT_CTX_VALID(ctx);
19495
19496 obj = duk_get_hobject(ctx, idx);
19497 if (obj) {
19498 return (DUK_HOBJECT_GET_CLASS_NUMBER(obj) == DUK_HOBJECT_CLASS_ARRAY ? 1 : 0);
19499 }
19500 return 0;
19501}
19502
19503DUK_EXTERNAL duk_bool_t duk_is_function(duk_context *ctx, duk_idx_t idx) {
19504 duk_tval *tv;
19505
19506 DUK_ASSERT_CTX_VALID(ctx);
19507
19508 tv = duk_get_tval_or_unused(ctx, idx);
19509 if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
19510 return 1;
19511 }
19512 return duk__obj_flag_any_default_false(ctx,
19513 idx,
19514 DUK_HOBJECT_FLAG_COMPFUNC |
19515 DUK_HOBJECT_FLAG_NATFUNC |
19516 DUK_HOBJECT_FLAG_BOUNDFUNC);
19517}
19518
19519DUK_EXTERNAL duk_bool_t duk_is_c_function(duk_context *ctx, duk_idx_t idx) {
19520 DUK_ASSERT_CTX_VALID(ctx);
19521 return duk__obj_flag_any_default_false(ctx,
19522 idx,
19523 DUK_HOBJECT_FLAG_NATFUNC);
19524}
19525
19526DUK_EXTERNAL duk_bool_t duk_is_ecmascript_function(duk_context *ctx, duk_idx_t idx) {
19527 DUK_ASSERT_CTX_VALID(ctx);
19528 return duk__obj_flag_any_default_false(ctx,
19529 idx,
19530 DUK_HOBJECT_FLAG_COMPFUNC);
19531}
19532
19533DUK_EXTERNAL duk_bool_t duk_is_bound_function(duk_context *ctx, duk_idx_t idx) {
19534 DUK_ASSERT_CTX_VALID(ctx);
19535 return duk__obj_flag_any_default_false(ctx,
19536 idx,
19537 DUK_HOBJECT_FLAG_BOUNDFUNC);
19538}
19539
19540DUK_EXTERNAL duk_bool_t duk_is_thread(duk_context *ctx, duk_idx_t idx) {
19541 DUK_ASSERT_CTX_VALID(ctx);
19542 return duk__obj_flag_any_default_false(ctx,
19543 idx,
19544 DUK_HOBJECT_FLAG_THREAD);
19545}
19546
19547DUK_EXTERNAL duk_bool_t duk_is_fixed_buffer(duk_context *ctx, duk_idx_t idx) {
19548 duk_tval *tv;
19549
19550 DUK_ASSERT_CTX_VALID(ctx);
19551
19552 tv = duk_get_tval_or_unused(ctx, idx);
19553 DUK_ASSERT(tv != NULL);
19554 if (DUK_TVAL_IS_BUFFER(tv)) {
19555 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
19556 DUK_ASSERT(h != NULL);
19557 return (DUK_HBUFFER_HAS_DYNAMIC(h) ? 0 : 1);
19558 }
19559 return 0;
19560}
19561
19562DUK_EXTERNAL duk_bool_t duk_is_dynamic_buffer(duk_context *ctx, duk_idx_t idx) {
19563 duk_tval *tv;
19564
19565 DUK_ASSERT_CTX_VALID(ctx);
19566
19567 tv = duk_get_tval_or_unused(ctx, idx);
19568 DUK_ASSERT(tv != NULL);
19569 if (DUK_TVAL_IS_BUFFER(tv)) {
19570 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
19571 DUK_ASSERT(h != NULL);
19572 return (DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h) ? 1 : 0);
19573 }
19574 return 0;
19575}
19576
19577DUK_EXTERNAL duk_bool_t duk_is_external_buffer(duk_context *ctx, duk_idx_t idx) {
19578 duk_tval *tv;
19579
19580 DUK_ASSERT_CTX_VALID(ctx);
19581
19582 tv = duk_get_tval_or_unused(ctx, idx);
19583 DUK_ASSERT(tv != NULL);
19584 if (DUK_TVAL_IS_BUFFER(tv)) {
19585 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
19586 DUK_ASSERT(h != NULL);
19587 return (DUK_HBUFFER_HAS_DYNAMIC(h) && DUK_HBUFFER_HAS_EXTERNAL(h) ? 1 : 0);
19588 }
19589 return 0;
19590}
19591
19592DUK_EXTERNAL duk_errcode_t duk_get_error_code(duk_context *ctx, duk_idx_t idx) {
19593 duk_hthread *thr = (duk_hthread *) ctx;
19594 duk_hobject *h;
19595 duk_uint_t sanity;
19596
19597 DUK_ASSERT_CTX_VALID(ctx);
19598
19599 h = duk_get_hobject(ctx, idx);
19600
19601 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
19602 do {
19603 if (!h) {
19604 return DUK_ERR_NONE;
19605 }
19606 if (h == thr->builtins[DUK_BIDX_EVAL_ERROR_PROTOTYPE]) {
19607 return DUK_ERR_EVAL_ERROR;
19608 }
19609 if (h == thr->builtins[DUK_BIDX_RANGE_ERROR_PROTOTYPE]) {
19610 return DUK_ERR_RANGE_ERROR;
19611 }
19612 if (h == thr->builtins[DUK_BIDX_REFERENCE_ERROR_PROTOTYPE]) {
19613 return DUK_ERR_REFERENCE_ERROR;
19614 }
19615 if (h == thr->builtins[DUK_BIDX_SYNTAX_ERROR_PROTOTYPE]) {
19616 return DUK_ERR_SYNTAX_ERROR;
19617 }
19618 if (h == thr->builtins[DUK_BIDX_TYPE_ERROR_PROTOTYPE]) {
19619 return DUK_ERR_TYPE_ERROR;
19620 }
19621 if (h == thr->builtins[DUK_BIDX_URI_ERROR_PROTOTYPE]) {
19622 return DUK_ERR_URI_ERROR;
19623 }
19624 if (h == thr->builtins[DUK_BIDX_ERROR_PROTOTYPE]) {
19625 return DUK_ERR_ERROR;
19626 }
19627
19628 h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
19629 } while (--sanity > 0);
19630
19631 return DUK_ERR_NONE;
19632}
19633
19634/*
19635 * Pushers
19636 */
19637
19638DUK_INTERNAL void duk_push_tval(duk_context *ctx, duk_tval *tv) {
19639 duk_hthread *thr;
19640 duk_tval *tv_slot;
19641
19642 DUK_ASSERT_CTX_VALID(ctx);
19643 DUK_ASSERT(tv != NULL);
19644 thr = (duk_hthread *) ctx;
19645 DUK__CHECK_SPACE();
19646 tv_slot = thr->valstack_top++;
19647 DUK_TVAL_SET_TVAL(tv_slot, tv);
19648 DUK_TVAL_INCREF(thr, tv); /* no side effects */
19649}
19650
19651DUK_EXTERNAL void duk_push_undefined(duk_context *ctx) {
19652 duk_hthread *thr;
19653
19654 DUK_ASSERT_CTX_VALID(ctx);
19655 thr = (duk_hthread *) ctx;
19656 DUK__CHECK_SPACE();
19657
19658 /* Because value stack init policy is 'undefined above top',
19659 * we don't need to write, just assert.
19660 */
19661 thr->valstack_top++;
19662 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top - 1));
19663}
19664
19665DUK_EXTERNAL void duk_push_null(duk_context *ctx) {
19666 duk_hthread *thr;
19667 duk_tval *tv_slot;
19668
19669 DUK_ASSERT_CTX_VALID(ctx);
19670 thr = (duk_hthread *) ctx;
19671 DUK__CHECK_SPACE();
19672 tv_slot = thr->valstack_top++;
19673 DUK_TVAL_SET_NULL(tv_slot);
19674}
19675
19676DUK_EXTERNAL void duk_push_boolean(duk_context *ctx, duk_bool_t val) {
19677 duk_hthread *thr;
19678 duk_tval *tv_slot;
19679 duk_small_int_t b;
19680
19681 DUK_ASSERT_CTX_VALID(ctx);
19682 thr = (duk_hthread *) ctx;
19683 DUK__CHECK_SPACE();
19684 b = (val ? 1 : 0); /* ensure value is 1 or 0 (not other non-zero) */
19685 tv_slot = thr->valstack_top++;
19686 DUK_TVAL_SET_BOOLEAN(tv_slot, b);
19687}
19688
19689DUK_EXTERNAL void duk_push_true(duk_context *ctx) {
19690 duk_hthread *thr;
19691 duk_tval *tv_slot;
19692
19693 DUK_ASSERT_CTX_VALID(ctx);
19694 thr = (duk_hthread *) ctx;
19695 DUK__CHECK_SPACE();
19696 tv_slot = thr->valstack_top++;
19697 DUK_TVAL_SET_BOOLEAN_TRUE(tv_slot);
19698}
19699
19700DUK_EXTERNAL void duk_push_false(duk_context *ctx) {
19701 duk_hthread *thr;
19702 duk_tval *tv_slot;
19703
19704 DUK_ASSERT_CTX_VALID(ctx);
19705 thr = (duk_hthread *) ctx;
19706 DUK__CHECK_SPACE();
19707 tv_slot = thr->valstack_top++;
19708 DUK_TVAL_SET_BOOLEAN_FALSE(tv_slot);
19709}
19710
19711/* normalize NaN which may not match our canonical internal NaN */
19712DUK_EXTERNAL void duk_push_number(duk_context *ctx, duk_double_t val) {
19713 duk_hthread *thr;
19714 duk_tval *tv_slot;
19716
19717 DUK_ASSERT_CTX_VALID(ctx);
19718 thr = (duk_hthread *) ctx;
19719 DUK__CHECK_SPACE();
19720 du.d = val;
19721 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
19722 tv_slot = thr->valstack_top++;
19723 DUK_TVAL_SET_NUMBER(tv_slot, du.d);
19724}
19725
19726DUK_EXTERNAL void duk_push_int(duk_context *ctx, duk_int_t val) {
19727#if defined(DUK_USE_FASTINT)
19728 duk_hthread *thr;
19729 duk_tval *tv_slot;
19730
19731 DUK_ASSERT_CTX_VALID(ctx);
19732 thr = (duk_hthread *) ctx;
19733 DUK__CHECK_SPACE();
19734 tv_slot = thr->valstack_top++;
19735#if DUK_INT_MAX <= 0x7fffffffL
19736 DUK_TVAL_SET_I32(tv_slot, (duk_int32_t) val);
19737#else
19738 if (val >= DUK_FASTINT_MIN && val <= DUK_FASTINT_MAX) {
19739 DUK_TVAL_SET_FASTINT(tv_slot, (duk_int64_t) val);
19740 } else {
19741 duk_double_t = (duk_double_t) val;
19742 DUK_TVAL_SET_NUMBER(tv_slot, d);
19743 }
19744#endif
19745#else /* DUK_USE_FASTINT */
19746 duk_hthread *thr;
19747 duk_tval *tv_slot;
19748 duk_double_t d;
19749
19750 DUK_ASSERT_CTX_VALID(ctx);
19751 thr = (duk_hthread *) ctx;
19752 DUK__CHECK_SPACE();
19753 d = (duk_double_t) val;
19754 tv_slot = thr->valstack_top++;
19755 DUK_TVAL_SET_NUMBER(tv_slot, d);
19756#endif /* DUK_USE_FASTINT */
19757}
19758
19759DUK_EXTERNAL void duk_push_uint(duk_context *ctx, duk_uint_t val) {
19760#if defined(DUK_USE_FASTINT)
19761 duk_hthread *thr;
19762 duk_tval *tv_slot;
19763
19764 DUK_ASSERT_CTX_VALID(ctx);
19765 thr = (duk_hthread *) ctx;
19766 DUK__CHECK_SPACE();
19767 tv_slot = thr->valstack_top++;
19768#if DUK_UINT_MAX <= 0xffffffffUL
19769 DUK_TVAL_SET_U32(tv_slot, (duk_uint32_t) val);
19770#else
19771 if (val <= DUK_FASTINT_MAX) { /* val is unsigned so >= 0 */
19772 /* XXX: take advantage of val being unsigned, no need to mask */
19773 DUK_TVAL_SET_FASTINT(tv_slot, (duk_int64_t) val);
19774 } else {
19775 duk_double_t = (duk_double_t) val;
19776 DUK_TVAL_SET_NUMBER(tv_slot, d);
19777 }
19778#endif
19779#else /* DUK_USE_FASTINT */
19780 duk_hthread *thr;
19781 duk_tval *tv_slot;
19782 duk_double_t d;
19783
19784 DUK_ASSERT_CTX_VALID(ctx);
19785 thr = (duk_hthread *) ctx;
19786 DUK__CHECK_SPACE();
19787 d = (duk_double_t) val;
19788 tv_slot = thr->valstack_top++;
19789 DUK_TVAL_SET_NUMBER(tv_slot, d);
19790#endif /* DUK_USE_FASTINT */
19791}
19792
19793DUK_EXTERNAL void duk_push_nan(duk_context *ctx) {
19794 duk_hthread *thr;
19795 duk_tval *tv_slot;
19797
19798 DUK_ASSERT_CTX_VALID(ctx);
19799 thr = (duk_hthread *) ctx;
19800 DUK__CHECK_SPACE();
19801 DUK_DBLUNION_SET_NAN(&du);
19802 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
19803 tv_slot = thr->valstack_top++;
19804 DUK_TVAL_SET_NUMBER(tv_slot, du.d);
19805}
19806
19807DUK_EXTERNAL const char *duk_push_lstring(duk_context *ctx, const char *str, duk_size_t len) {
19808 duk_hthread *thr = (duk_hthread *) ctx;
19809 duk_hstring *h;
19810 duk_tval *tv_slot;
19811
19812 DUK_ASSERT_CTX_VALID(ctx);
19813
19814 /* check stack before interning (avoid hanging temp) */
19815 if (thr->valstack_top >= thr->valstack_end) {
19816 DUK_ERROR_RANGE_PUSH_BEYOND(thr);
19817 }
19818
19819 /* NULL with zero length represents an empty string; NULL with higher
19820 * length is also now trated like an empty string although it is
19821 * a bit dubious. This is unlike duk_push_string() which pushes a
19822 * 'null' if the input string is a NULL.
19823 */
19824 if (!str) {
19825 len = 0;
19826 }
19827
19828 /* Check for maximum string length */
19829 if (len > DUK_HSTRING_MAX_BYTELEN) {
19830 DUK_ERROR_RANGE(thr, DUK_STR_STRING_TOO_LONG);
19831 }
19832
19833 h = duk_heap_string_intern_checked(thr, (const duk_uint8_t *) str, (duk_uint32_t) len);
19834 DUK_ASSERT(h != NULL);
19835
19836 tv_slot = thr->valstack_top++;
19837 DUK_TVAL_SET_STRING(tv_slot, h);
19838 DUK_HSTRING_INCREF(thr, h); /* no side effects */
19839
19840 return (const char *) DUK_HSTRING_GET_DATA(h);
19841}
19842
19843DUK_EXTERNAL const char *duk_push_string(duk_context *ctx, const char *str) {
19844 DUK_ASSERT_CTX_VALID(ctx);
19845
19846 if (str) {
19847 return duk_push_lstring(ctx, str, DUK_STRLEN(str));
19848 } else {
19849 duk_push_null(ctx);
19850 return NULL;
19851 }
19852}
19853
19854DUK_EXTERNAL void duk_push_pointer(duk_context *ctx, void *val) {
19855 duk_hthread *thr;
19856 duk_tval *tv_slot;
19857
19858 DUK_ASSERT_CTX_VALID(ctx);
19859 thr = (duk_hthread *) ctx;
19860 DUK__CHECK_SPACE();
19861 tv_slot = thr->valstack_top++;
19862 DUK_TVAL_SET_POINTER(tv_slot, val);
19863}
19864
19865DUK_INTERNAL duk_hstring *duk_push_uint_to_hstring(duk_context *ctx, duk_uint_t i) {
19866 duk_hstring *h_tmp;
19867
19868 /* XXX: this could be a direct DUK_SPRINTF to a buffer followed by duk_push_string() */
19869 duk_push_uint(ctx, (duk_uint_t) i);
19870 h_tmp = duk_to_hstring_m1(ctx);
19871 DUK_ASSERT(h_tmp != NULL);
19872 return h_tmp;
19873}
19874
19875DUK_LOCAL void duk__push_this_helper(duk_context *ctx, duk_small_uint_t check_object_coercible) {
19876 duk_hthread *thr;
19877 duk_tval *tv_slot;
19878
19879 DUK_ASSERT_CTX_VALID(ctx);
19880 DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */
19881 thr = (duk_hthread *) ctx;
19882 DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
19883 DUK__CHECK_SPACE();
19884
19885 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* because of valstack init policy */
19886 tv_slot = thr->valstack_top++;
19887
19888 if (DUK_UNLIKELY(thr->callstack_top == 0)) {
19889 if (check_object_coercible) {
19890 goto type_error;
19891 }
19892 /* 'undefined' already on stack top */
19893 } else {
19894 duk_tval *tv;
19895
19896 /* 'this' binding is just before current activation's bottom */
19897 DUK_ASSERT(thr->valstack_bottom > thr->valstack);
19898 tv = thr->valstack_bottom - 1;
19899 if (check_object_coercible &&
19900 (DUK_TVAL_IS_UNDEFINED(tv) || DUK_TVAL_IS_NULL(tv))) {
19901 /* XXX: better macro for DUK_TVAL_IS_UNDEFINED_OR_NULL(tv) */
19902 goto type_error;
19903 }
19904
19905 DUK_TVAL_SET_TVAL(tv_slot, tv);
19906 DUK_TVAL_INCREF(thr, tv);
19907 }
19908 return;
19909
19910 type_error:
19911 DUK_ERROR_TYPE(thr, DUK_STR_NOT_OBJECT_COERCIBLE);
19912}
19913
19914DUK_EXTERNAL void duk_push_this(duk_context *ctx) {
19915 DUK_ASSERT_CTX_VALID(ctx);
19916
19917 duk__push_this_helper(ctx, 0 /*check_object_coercible*/);
19918}
19919
19920DUK_INTERNAL void duk_push_this_check_object_coercible(duk_context *ctx) {
19921 DUK_ASSERT_CTX_VALID(ctx);
19922
19923 duk__push_this_helper(ctx, 1 /*check_object_coercible*/);
19924}
19925
19926DUK_INTERNAL duk_hobject *duk_push_this_coercible_to_object(duk_context *ctx) {
19927 duk_hobject *h;
19928
19929 DUK_ASSERT_CTX_VALID(ctx);
19930
19931 duk__push_this_helper(ctx, 1 /*check_object_coercible*/);
19932 h = duk_to_hobject(ctx, -1);
19933 DUK_ASSERT(h != NULL);
19934 return h;
19935}
19936
19937DUK_INTERNAL duk_hstring *duk_push_this_coercible_to_string(duk_context *ctx) {
19938 DUK_ASSERT_CTX_VALID(ctx);
19939
19940 duk__push_this_helper(ctx, 1 /*check_object_coercible*/);
19941 return duk_to_hstring_m1(ctx); /* This will reject all Symbol values; accepts Symbol objects. */
19942}
19943
19944DUK_INTERNAL duk_tval *duk_get_borrowed_this_tval(duk_context *ctx) {
19945 duk_hthread *thr;
19946
19947 DUK_ASSERT(ctx != NULL);
19948 thr = (duk_hthread *) ctx;
19949
19950 DUK_ASSERT(thr->callstack_top > 0); /* caller required to know */
19951 DUK_ASSERT(thr->valstack_bottom > thr->valstack); /* consequence of above */
19952 DUK_ASSERT(thr->valstack_bottom - 1 >= thr->valstack); /* 'this' binding exists */
19953
19954 return thr->valstack_bottom - 1;
19955}
19956
19957DUK_EXTERNAL void duk_push_current_function(duk_context *ctx) {
19958 duk_hthread *thr = (duk_hthread *) ctx;
19959 duk_activation *act;
19960
19961 DUK_ASSERT_CTX_VALID(ctx);
19962 DUK_ASSERT(thr != NULL);
19963 DUK_ASSERT_DISABLE(thr->callstack_top >= 0);
19964 DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
19965
19966 act = duk_hthread_get_current_activation(thr);
19967 if (act) {
19968 duk_push_tval(ctx, &act->tv_func);
19969 } else {
19970 duk_push_undefined(ctx);
19971 }
19972}
19973
19974DUK_EXTERNAL void duk_push_current_thread(duk_context *ctx) {
19975 duk_hthread *thr = (duk_hthread *) ctx;
19976
19977 DUK_ASSERT_CTX_VALID(ctx);
19978 DUK_ASSERT(thr != NULL);
19979
19980 if (thr->heap->curr_thread) {
19981 duk_push_hobject(ctx, (duk_hobject *) thr->heap->curr_thread);
19982 } else {
19983 duk_push_undefined(ctx);
19984 }
19985}
19986
19987DUK_EXTERNAL void duk_push_global_object(duk_context *ctx) {
19988 DUK_ASSERT_CTX_VALID(ctx);
19989
19990 duk_push_hobject_bidx(ctx, DUK_BIDX_GLOBAL);
19991}
19992
19993/* XXX: size optimize */
19994DUK_LOCAL void duk__push_stash(duk_context *ctx) {
19995 DUK_ASSERT_CTX_VALID(ctx);
19996 if (!duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_VALUE)) {
19997 DUK_DDD(DUK_DDDPRINT("creating heap/global/thread stash on first use"));
19998 duk_pop(ctx);
19999 duk_push_bare_object(ctx);
20000 duk_dup_top(ctx);
20001 duk_xdef_prop_stridx_short(ctx, -3, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_C); /* [ ... parent stash stash ] -> [ ... parent stash ] */
20002 }
20003 duk_remove_m2(ctx);
20004}
20005
20006DUK_EXTERNAL void duk_push_heap_stash(duk_context *ctx) {
20007 duk_hthread *thr = (duk_hthread *) ctx;
20008 duk_heap *heap;
20009 DUK_ASSERT_CTX_VALID(ctx);
20010 heap = thr->heap;
20011 DUK_ASSERT(heap->heap_object != NULL);
20012 duk_push_hobject(ctx, heap->heap_object);
20013 duk__push_stash(ctx);
20014}
20015
20016DUK_EXTERNAL void duk_push_global_stash(duk_context *ctx) {
20017 DUK_ASSERT_CTX_VALID(ctx);
20018 duk_push_global_object(ctx);
20019 duk__push_stash(ctx);
20020}
20021
20022DUK_EXTERNAL void duk_push_thread_stash(duk_context *ctx, duk_context *target_ctx) {
20023 duk_hthread *thr = (duk_hthread *) ctx;
20024 DUK_ASSERT_CTX_VALID(ctx);
20025 if (!target_ctx) {
20026 DUK_ERROR_TYPE_INVALID_ARGS(thr);
20027 return; /* not reached */
20028 }
20029 duk_push_hobject(ctx, (duk_hobject *) target_ctx);
20030 duk__push_stash(ctx);
20031}
20032
20033/* XXX: duk_ssize_t would be useful here */
20034DUK_LOCAL duk_int_t duk__try_push_vsprintf(duk_context *ctx, void *buf, duk_size_t sz, const char *fmt, va_list ap) {
20035 duk_int_t len;
20036
20037 DUK_ASSERT_CTX_VALID(ctx);
20038 DUK_UNREF(ctx);
20039
20040 /* NUL terminator handling doesn't matter here */
20041 len = DUK_VSNPRINTF((char *) buf, sz, fmt, ap);
20042 if (len < (duk_int_t) sz) {
20043 /* Return value of 'sz' or more indicates output was (potentially)
20044 * truncated.
20045 */
20046 return (duk_int_t) len;
20047 }
20048 return -1;
20049}
20050
20051DUK_EXTERNAL const char *duk_push_vsprintf(duk_context *ctx, const char *fmt, va_list ap) {
20052 duk_hthread *thr = (duk_hthread *) ctx;
20053 duk_uint8_t stack_buf[DUK_PUSH_SPRINTF_INITIAL_SIZE];
20054 duk_size_t sz = DUK_PUSH_SPRINTF_INITIAL_SIZE;
20055 duk_bool_t pushed_buf = 0;
20056 void *buf;
20057 duk_int_t len; /* XXX: duk_ssize_t */
20058 const char *res;
20059
20060 DUK_ASSERT_CTX_VALID(ctx);
20061
20062 /* special handling of fmt==NULL */
20063 if (!fmt) {
20064 duk_hstring *h_str;
20065 duk_push_hstring_empty(ctx);
20066 h_str = duk_known_hstring(ctx, -1);
20067 return (const char *) DUK_HSTRING_GET_DATA(h_str);
20068 }
20069
20070 /* initial estimate based on format string */
20071 sz = DUK_STRLEN(fmt) + 16; /* format plus something to avoid just missing */
20072 if (sz < DUK_PUSH_SPRINTF_INITIAL_SIZE) {
20073 sz = DUK_PUSH_SPRINTF_INITIAL_SIZE;
20074 }
20075 DUK_ASSERT(sz > 0);
20076
20077 /* Try to make do with a stack buffer to avoid allocating a temporary buffer.
20078 * This works 99% of the time which is quite nice.
20079 */
20080 for (;;) {
20081 va_list ap_copy; /* copied so that 'ap' can be reused */
20082
20083 if (sz <= sizeof(stack_buf)) {
20084 buf = stack_buf;
20085 } else if (!pushed_buf) {
20086 pushed_buf = 1;
20087 buf = duk_push_dynamic_buffer(ctx, sz);
20088 } else {
20089 buf = duk_resize_buffer(ctx, -1, sz);
20090 }
20091 DUK_ASSERT(buf != NULL);
20092
20093 DUK_VA_COPY(ap_copy, ap);
20094 len = duk__try_push_vsprintf(ctx, buf, sz, fmt, ap_copy);
20095 va_end(ap_copy);
20096 if (len >= 0) {
20097 break;
20098 }
20099
20100 /* failed, resize and try again */
20101 sz = sz * 2;
20102 if (sz >= DUK_PUSH_SPRINTF_SANITY_LIMIT) {
20103 DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG);
20104 }
20105 }
20106
20107 /* Cannot use duk_buffer_to_string() on the buffer because it is
20108 * usually larger than 'len'; 'buf' is also usually a stack buffer.
20109 */
20110 res = duk_push_lstring(ctx, (const char *) buf, (duk_size_t) len); /* [ buf? res ] */
20111 if (pushed_buf) {
20112 duk_remove_m2(ctx);
20113 }
20114 return res;
20115}
20116
20117DUK_EXTERNAL const char *duk_push_sprintf(duk_context *ctx, const char *fmt, ...) {
20118 va_list ap;
20119 const char *ret;
20120
20121 DUK_ASSERT_CTX_VALID(ctx);
20122
20123 /* allow fmt==NULL */
20124 va_start(ap, fmt);
20125 ret = duk_push_vsprintf(ctx, fmt, ap);
20126 va_end(ap);
20127
20128 return ret;
20129}
20130
20131DUK_INTERNAL duk_hobject *duk_push_object_helper(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) {
20132 duk_hthread *thr = (duk_hthread *) ctx;
20133 duk_tval *tv_slot;
20134 duk_hobject *h;
20135
20136 DUK_ASSERT_CTX_VALID(ctx);
20137 DUK_ASSERT(prototype_bidx == -1 ||
20138 (prototype_bidx >= 0 && prototype_bidx < DUK_NUM_BUILTINS));
20139
20140 /* check stack first */
20141 if (thr->valstack_top >= thr->valstack_end) {
20142 DUK_ERROR_RANGE_PUSH_BEYOND(thr);
20143 }
20144
20145 h = duk_hobject_alloc(thr->heap, hobject_flags_and_class);
20146 if (!h) {
20147 DUK_ERROR_ALLOC_FAILED(thr);
20148 }
20149
20150 DUK_DDD(DUK_DDDPRINT("created object with flags: 0x%08lx", (unsigned long) h->hdr.h_flags));
20151
20152 tv_slot = thr->valstack_top;
20153 DUK_TVAL_SET_OBJECT(tv_slot, h);
20154 DUK_HOBJECT_INCREF(thr, h); /* no side effects */
20155 thr->valstack_top++;
20156
20157 /* object is now reachable */
20158
20159 if (prototype_bidx >= 0) {
20160 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[prototype_bidx]);
20161 } else {
20162 DUK_ASSERT(prototype_bidx == -1);
20163 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h) == NULL);
20164 }
20165
20166 return h;
20167}
20168
20169DUK_INTERNAL duk_hobject *duk_push_object_helper_proto(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_hobject *proto) {
20170 duk_hthread *thr = (duk_hthread *) ctx;
20171 duk_hobject *h;
20172
20173 DUK_ASSERT_CTX_VALID(ctx);
20174
20175 h = duk_push_object_helper(ctx, hobject_flags_and_class, -1);
20176 DUK_ASSERT(h != NULL);
20177 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h) == NULL);
20178 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, proto);
20179 return h;
20180}
20181
20182DUK_EXTERNAL duk_idx_t duk_push_object(duk_context *ctx) {
20183 DUK_ASSERT_CTX_VALID(ctx);
20184
20185 (void) duk_push_object_helper(ctx,
20186 DUK_HOBJECT_FLAG_EXTENSIBLE |
20187 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
20188 DUK_BIDX_OBJECT_PROTOTYPE);
20189 return duk_get_top_index_unsafe(ctx);
20190}
20191
20192DUK_EXTERNAL duk_idx_t duk_push_array(duk_context *ctx) {
20193 duk_hthread *thr = (duk_hthread *) ctx;
20194 duk_uint_t flags;
20195 duk_harray *obj;
20196 duk_idx_t ret;
20197 duk_tval *tv_slot;
20198
20199 DUK_ASSERT_CTX_VALID(ctx);
20200
20201 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
20202 DUK_HOBJECT_FLAG_ARRAY_PART |
20203 DUK_HOBJECT_FLAG_EXOTIC_ARRAY |
20204 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAY);
20205
20206 obj = duk_harray_alloc(thr->heap, flags);
20207 if (!obj) {
20208 DUK_ERROR_ALLOC_FAILED(thr);
20209 }
20210
20211 /* XXX: since prototype is NULL, could save a check */
20212 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_ARRAY_PROTOTYPE]);
20213
20214 tv_slot = thr->valstack_top;
20215 DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
20216 DUK_HOBJECT_INCREF(thr, obj); /* XXX: could preallocate with refcount = 1 */
20217 ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
20218 thr->valstack_top++;
20219
20220 DUK_ASSERT(obj->length == 0); /* Array .length starts at zero. */
20221 return ret;
20222}
20223
20224DUK_INTERNAL duk_harray *duk_push_harray(duk_context *ctx) {
20225 /* XXX: API call could do this directly, cast to void in API macro. */
20226 duk_hthread *thr;
20227 duk_harray *a;
20228
20229 thr = (duk_hthread *) ctx;
20230 (void) duk_push_array(ctx);
20231 DUK_ASSERT(DUK_TVAL_IS_OBJECT(thr->valstack_top - 1));
20232 a = (duk_harray *) DUK_TVAL_GET_OBJECT(thr->valstack_top - 1);
20233 DUK_ASSERT(a != NULL);
20234 return a;
20235}
20236
20237/* Push a duk_harray with preallocated size (.length also set to match size).
20238 * Caller may then populate array part of the duk_harray directly.
20239 */
20240DUK_INTERNAL duk_harray *duk_push_harray_with_size(duk_context *ctx, duk_uint32_t size) {
20241 duk_harray *a;
20242
20243 a = duk_push_harray(ctx);
20244
20245 duk_hobject_realloc_props((duk_hthread *) ctx,
20246 (duk_hobject *) a,
20247 0,
20248 size,
20249 0,
20250 0);
20251 a->length = size;
20252 return a;
20253}
20254
20255DUK_EXTERNAL duk_idx_t duk_push_thread_raw(duk_context *ctx, duk_uint_t flags) {
20256 duk_hthread *thr = (duk_hthread *) ctx;
20257 duk_hthread *obj;
20258 duk_idx_t ret;
20259 duk_tval *tv_slot;
20260
20261 DUK_ASSERT_CTX_VALID(ctx);
20262
20263 /* check stack first */
20264 if (thr->valstack_top >= thr->valstack_end) {
20265 DUK_ERROR_RANGE_PUSH_BEYOND(thr);
20266 }
20267
20268 obj = duk_hthread_alloc(thr->heap,
20269 DUK_HOBJECT_FLAG_EXTENSIBLE |
20270 DUK_HOBJECT_FLAG_THREAD |
20271 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD));
20272 if (!obj) {
20273 DUK_ERROR_ALLOC_FAILED(thr);
20274 }
20275 obj->state = DUK_HTHREAD_STATE_INACTIVE;
20276#if defined(DUK_USE_ROM_STRINGS)
20277 /* Nothing to initialize, strs[] is in ROM. */
20278#else
20279#if defined(DUK_USE_HEAPPTR16)
20280 obj->strs16 = thr->strs16;
20281#else
20282 obj->strs = thr->strs;
20283#endif
20284#endif
20285 DUK_DDD(DUK_DDDPRINT("created thread object with flags: 0x%08lx", (unsigned long) obj->obj.hdr.h_flags));
20286
20287 /* make the new thread reachable */
20288 tv_slot = thr->valstack_top;
20289 DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
20290 DUK_HTHREAD_INCREF(thr, obj);
20291 ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
20292 thr->valstack_top++;
20293
20294 /* important to do this *after* pushing, to make the thread reachable for gc */
20295 if (!duk_hthread_init_stacks(thr->heap, obj)) {
20296 DUK_ERROR_ALLOC_FAILED(thr);
20297 }
20298
20299 /* initialize built-ins - either by copying or creating new ones */
20300 if (flags & DUK_THREAD_NEW_GLOBAL_ENV) {
20301 duk_hthread_create_builtin_objects(obj);
20302 } else {
20303 duk_hthread_copy_builtin_objects(thr, obj);
20304 }
20305
20306 /* default prototype (Note: 'obj' must be reachable) */
20307 /* XXX: since prototype is NULL, could save a check */
20308 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, obj->builtins[DUK_BIDX_THREAD_PROTOTYPE]);
20309
20310 /* Initial stack size satisfies the stack spare constraints so there
20311 * is no need to require stack here.
20312 */
20313 DUK_ASSERT(DUK_VALSTACK_INITIAL_SIZE >=
20314 DUK_VALSTACK_API_ENTRY_MINIMUM + DUK_VALSTACK_INTERNAL_EXTRA);
20315
20316 return ret;
20317}
20318
20319DUK_INTERNAL duk_hcompfunc *duk_push_hcompfunc(duk_context *ctx) {
20320 duk_hthread *thr = (duk_hthread *) ctx;
20321 duk_hcompfunc *obj;
20322 duk_tval *tv_slot;
20323
20324 DUK_ASSERT_CTX_VALID(ctx);
20325
20326 /* check stack first */
20327 if (thr->valstack_top >= thr->valstack_end) {
20328 DUK_ERROR_RANGE_PUSH_BEYOND(thr);
20329 }
20330
20331 /* Template functions are not strictly constructable (they don't
20332 * have a "prototype" property for instance), so leave the
20333 * DUK_HOBJECT_FLAG_CONSRUCTABLE flag cleared here.
20334 */
20335
20336 obj = duk_hcompfunc_alloc(thr->heap,
20337 DUK_HOBJECT_FLAG_EXTENSIBLE |
20338 DUK_HOBJECT_FLAG_COMPFUNC |
20339 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION));
20340 if (!obj) {
20341 DUK_ERROR_ALLOC_FAILED(thr);
20342 }
20343
20344 DUK_DDD(DUK_DDDPRINT("created compiled function object with flags: 0x%08lx", (unsigned long) obj->obj.hdr.h_flags));
20345
20346 tv_slot = thr->valstack_top;
20347 DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
20348 DUK_HOBJECT_INCREF(thr, obj);
20349 thr->valstack_top++;
20350
20351 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
20352
20353 return obj;
20354}
20355
20356DUK_LOCAL duk_idx_t duk__push_c_function_raw(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_uint_t flags) {
20357 duk_hthread *thr = (duk_hthread *) ctx;
20358 duk_hnatfunc *obj;
20359 duk_idx_t ret;
20360 duk_tval *tv_slot;
20361 duk_int16_t func_nargs;
20362
20363 DUK_ASSERT_CTX_VALID(ctx);
20364
20365 /* check stack first */
20366 if (thr->valstack_top >= thr->valstack_end) {
20367 DUK_ERROR_RANGE_PUSH_BEYOND(thr);
20368 }
20369 if (func == NULL) {
20370 goto api_error;
20371 }
20372 if (nargs >= 0 && nargs < DUK_HNATFUNC_NARGS_MAX) {
20373 func_nargs = (duk_int16_t) nargs;
20374 } else if (nargs == DUK_VARARGS) {
20375 func_nargs = DUK_HNATFUNC_NARGS_VARARGS;
20376 } else {
20377 goto api_error;
20378 }
20379
20380 obj = duk_hnatfunc_alloc(thr->heap, flags);
20381 if (!obj) {
20382 DUK_ERROR_ALLOC_FAILED(thr);
20383 }
20384
20385 obj->func = func;
20386 obj->nargs = func_nargs;
20387
20388 DUK_DDD(DUK_DDDPRINT("created native function object with flags: 0x%08lx, nargs=%ld",
20389 (unsigned long) obj->obj.hdr.h_flags, (long) obj->nargs));
20390
20391 tv_slot = thr->valstack_top;
20392 DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
20393 DUK_HOBJECT_INCREF(thr, obj);
20394 ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
20395 thr->valstack_top++;
20396
20397 /* default prototype (Note: 'obj' must be reachable) */
20398 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
20399
20400 return ret;
20401
20402 api_error:
20403 DUK_ERROR_TYPE_INVALID_ARGS(thr);
20404 return 0; /* not reached */
20405}
20406
20407DUK_EXTERNAL duk_idx_t duk_push_c_function(duk_context *ctx, duk_c_function func, duk_int_t nargs) {
20408 duk_uint_t flags;
20409
20410 DUK_ASSERT_CTX_VALID(ctx);
20411
20412 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
20413 DUK_HOBJECT_FLAG_CONSTRUCTABLE |
20414 DUK_HOBJECT_FLAG_NATFUNC |
20415 DUK_HOBJECT_FLAG_NEWENV |
20416 DUK_HOBJECT_FLAG_STRICT |
20417 DUK_HOBJECT_FLAG_NOTAIL |
20418 DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC |
20419 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
20420
20421 return duk__push_c_function_raw(ctx, func, nargs, flags);
20422}
20423
20424DUK_INTERNAL void duk_push_c_function_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs) {
20425 duk_uint_t flags;
20426
20427 DUK_ASSERT_CTX_VALID(ctx);
20428
20429 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
20430 DUK_HOBJECT_FLAG_CONSTRUCTABLE |
20431 DUK_HOBJECT_FLAG_NATFUNC |
20432 DUK_HOBJECT_FLAG_NEWENV |
20433 DUK_HOBJECT_FLAG_STRICT |
20434 DUK_HOBJECT_FLAG_NOTAIL |
20435 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
20436
20437 (void) duk__push_c_function_raw(ctx, func, nargs, flags);
20438}
20439
20440DUK_INTERNAL void duk_push_c_function_noconstruct_noexotic(duk_context *ctx, duk_c_function func, duk_int_t nargs) {
20441 duk_uint_t flags;
20442
20443 DUK_ASSERT_CTX_VALID(ctx);
20444
20445 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
20446 DUK_HOBJECT_FLAG_NATFUNC |
20447 DUK_HOBJECT_FLAG_NEWENV |
20448 DUK_HOBJECT_FLAG_STRICT |
20449 DUK_HOBJECT_FLAG_NOTAIL |
20450 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION);
20451
20452 (void) duk__push_c_function_raw(ctx, func, nargs, flags);
20453}
20454
20455DUK_EXTERNAL duk_idx_t duk_push_c_lightfunc(duk_context *ctx, duk_c_function func, duk_idx_t nargs, duk_idx_t length, duk_int_t magic) {
20456 duk_hthread *thr = (duk_hthread *) ctx;
20457 duk_tval tv_tmp;
20458 duk_small_uint_t lf_flags;
20459
20460 DUK_ASSERT_CTX_VALID(ctx);
20461
20462 /* check stack first */
20463 if (thr->valstack_top >= thr->valstack_end) {
20464 DUK_ERROR_RANGE_PUSH_BEYOND(thr);
20465 }
20466
20467 if (nargs >= DUK_LFUNC_NARGS_MIN && nargs <= DUK_LFUNC_NARGS_MAX) {
20468 /* as is */
20469 } else if (nargs == DUK_VARARGS) {
20470 nargs = DUK_LFUNC_NARGS_VARARGS;
20471 } else {
20472 goto api_error;
20473 }
20474 if (!(length >= DUK_LFUNC_LENGTH_MIN && length <= DUK_LFUNC_LENGTH_MAX)) {
20475 goto api_error;
20476 }
20477 if (!(magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX)) {
20478 goto api_error;
20479 }
20480
20481 lf_flags = DUK_LFUNC_FLAGS_PACK(magic, length, nargs);
20482 DUK_TVAL_SET_LIGHTFUNC(&tv_tmp, func, lf_flags);
20483 duk_push_tval(ctx, &tv_tmp); /* XXX: direct valstack write */
20484 DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
20485 return ((duk_idx_t) (thr->valstack_top - thr->valstack_bottom)) - 1;
20486
20487 api_error:
20488 DUK_ERROR_TYPE_INVALID_ARGS(thr);
20489 return 0; /* not reached */
20490}
20491
20492#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
20493DUK_INTERNAL duk_hbufobj *duk_push_bufobj_raw(duk_context *ctx, duk_uint_t hobject_flags_and_class, duk_small_int_t prototype_bidx) {
20494 duk_hthread *thr = (duk_hthread *) ctx;
20495 duk_hbufobj *obj;
20496 duk_tval *tv_slot;
20497
20498 DUK_ASSERT(ctx != NULL);
20499 DUK_ASSERT(prototype_bidx >= 0);
20500
20501 /* check stack first */
20502 if (thr->valstack_top >= thr->valstack_end) {
20503 DUK_ERROR_RANGE_PUSH_BEYOND(thr);
20504 }
20505
20506 obj = duk_hbufobj_alloc(thr->heap, hobject_flags_and_class);
20507 if (!obj) {
20508 DUK_ERROR_ALLOC_FAILED(thr);
20509 }
20510
20511 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) obj, thr->builtins[prototype_bidx]);
20512 DUK_ASSERT_HBUFOBJ_VALID(obj);
20513
20514 tv_slot = thr->valstack_top;
20515 DUK_TVAL_SET_OBJECT(tv_slot, (duk_hobject *) obj);
20516 DUK_HOBJECT_INCREF(thr, obj);
20517 thr->valstack_top++;
20518
20519 return obj;
20520}
20521#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
20522
20523/* XXX: There's quite a bit of overlap with buffer creation handling in
20524 * duk_bi_buffer.c. Look for overlap and refactor.
20525 */
20526#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
20527#define DUK__PACK_ARGS(classnum,protobidx,elemtype,elemshift,istypedarray) \
20528 (((classnum) << 24) | ((protobidx) << 16) | ((elemtype) << 8) | ((elemshift) << 4) | (istypedarray))
20529
20530static const duk_uint32_t duk__bufobj_flags_lookup[] = {
20531 /* Node.js Buffers are Uint8Array instances which inherit from Buffer.prototype. */
20532 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_ARRAYBUFFER, DUK_BIDX_ARRAYBUFFER_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_ARRAYBUFFER */
20533 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8ARRAY, DUK_BIDX_NODEJS_BUFFER_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_NODEJS_BUFFER */
20534 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_DATAVIEW, DUK_BIDX_DATAVIEW_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 0), /* DUK_BUFOBJ_DATAVIEW */
20535 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT8ARRAY, DUK_BIDX_INT8ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_INT8, 0, 1), /* DUK_BUFOBJ_INT8ARRAY */
20536 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8ARRAY, DUK_BIDX_UINT8ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8, 0, 1), /* DUK_BUFOBJ_UINT8ARRAY */
20537 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY, DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT8CLAMPED, 0, 1), /* DUK_BUFOBJ_UINT8CLAMPEDARRAY */
20538 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT16ARRAY, DUK_BIDX_INT16ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_INT16, 1, 1), /* DUK_BUFOBJ_INT16ARRAY */
20539 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT16ARRAY, DUK_BIDX_UINT16ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT16, 1, 1), /* DUK_BUFOBJ_UINT16ARRAY */
20540 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_INT32ARRAY, DUK_BIDX_INT32ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_INT32, 2, 1), /* DUK_BUFOBJ_INT32ARRAY */
20541 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_UINT32ARRAY, DUK_BIDX_UINT32ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_UINT32, 2, 1), /* DUK_BUFOBJ_UINT32ARRAY */
20542 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT32ARRAY, DUK_BIDX_FLOAT32ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_FLOAT32, 2, 1), /* DUK_BUFOBJ_FLOAT32ARRAY */
20543 DUK__PACK_ARGS(DUK_HOBJECT_CLASS_FLOAT64ARRAY, DUK_BIDX_FLOAT64ARRAY_PROTOTYPE, DUK_HBUFOBJ_ELEM_FLOAT64, 3, 1) /* DUK_BUFOBJ_FLOAT64ARRAY */
20544};
20545#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
20546
20547#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
20548DUK_EXTERNAL void duk_push_buffer_object(duk_context *ctx, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags) {
20549 duk_hthread *thr;
20550 duk_hbufobj *h_bufobj;
20551 duk_hbuffer *h_val;
20552 duk_uint32_t tmp;
20553 duk_uint_t classnum;
20554 duk_uint_t protobidx;
20555 duk_uint_t lookupidx;
20556 duk_uint_t uint_offset, uint_length, uint_added;
20557
20558 DUK_ASSERT_CTX_VALID(ctx);
20559 thr = (duk_hthread *) ctx;
20560 DUK_UNREF(thr);
20561
20562 /* The underlying types for offset/length in duk_hbufobj is
20563 * duk_uint_t; make sure argument values fit and that
20564 * offset + length does not wrap.
20565 */
20566 uint_offset = (duk_uint_t) byte_offset;
20567 uint_length = (duk_uint_t) byte_length;
20568 if (sizeof(duk_size_t) != sizeof(duk_uint_t)) {
20569 if ((duk_size_t) uint_offset != byte_offset || (duk_size_t) uint_length != byte_length) {
20570 goto range_error;
20571 }
20572 }
20573 uint_added = uint_offset + uint_length;
20574 if (uint_added < uint_offset) {
20575 goto range_error;
20576 }
20577 DUK_ASSERT(uint_added >= uint_offset && uint_added >= uint_length);
20578
20579 DUK_ASSERT_DISABLE(flags >= 0); /* flags is unsigned */
20580 lookupidx = flags & 0x0f; /* 4 low bits */
20581 if (lookupidx >= sizeof(duk__bufobj_flags_lookup) / sizeof(duk_uint32_t)) {
20582 goto arg_error;
20583 }
20584 tmp = duk__bufobj_flags_lookup[lookupidx];
20585 classnum = tmp >> 24;
20586 protobidx = (tmp >> 16) & 0xff;
20587
20588 h_val = duk_require_hbuffer(ctx, idx_buffer);
20589 DUK_ASSERT(h_val != NULL);
20590
20591 h_bufobj = duk_push_bufobj_raw(ctx,
20592 DUK_HOBJECT_FLAG_EXTENSIBLE |
20593 DUK_HOBJECT_FLAG_BUFOBJ |
20594 DUK_HOBJECT_CLASS_AS_FLAGS(classnum),
20595 protobidx);
20596 DUK_ASSERT(h_bufobj != NULL);
20597
20598 h_bufobj->buf = h_val;
20599 DUK_HBUFFER_INCREF(thr, h_val);
20600 h_bufobj->offset = uint_offset;
20601 h_bufobj->length = uint_length;
20602 h_bufobj->shift = (tmp >> 4) & 0x0f;
20603 h_bufobj->elem_type = (tmp >> 8) & 0xff;
20604 h_bufobj->is_typedarray = tmp & 0x0f;
20605 DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
20606
20607 /* TypedArray views need an automatic ArrayBuffer which must be
20608 * provided as .buffer property of the view. The ArrayBuffer is
20609 * referenced via duk_hbufobj->buf_prop and an inherited .buffer
20610 * accessor returns it.
20611 *
20612 * The ArrayBuffer offset is always set to zero, so that if one
20613 * accesses the ArrayBuffer at the view's .byteOffset, the value
20614 * matches the view at index 0.
20615 */
20616 if (flags & DUK_BUFOBJ_CREATE_ARRBUF) {
20617 duk_hbufobj *h_arrbuf;
20618
20619 h_arrbuf = duk_push_bufobj_raw(ctx,
20620 DUK_HOBJECT_FLAG_EXTENSIBLE |
20621 DUK_HOBJECT_FLAG_BUFOBJ |
20622 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
20623 DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
20624 DUK_ASSERT(h_arrbuf != NULL);
20625
20626 h_arrbuf->buf = h_val;
20627 DUK_HBUFFER_INCREF(thr, h_val);
20628 h_arrbuf->offset = 0;
20629 h_arrbuf->length = uint_offset + uint_length; /* Wrap checked above. */
20630 DUK_ASSERT(h_arrbuf->shift == 0);
20631 h_arrbuf->elem_type = DUK_HBUFOBJ_ELEM_UINT8;
20632 DUK_ASSERT(h_arrbuf->is_typedarray == 0);
20633 DUK_ASSERT_HBUFOBJ_VALID(h_arrbuf);
20634 DUK_ASSERT(h_arrbuf->buf_prop == NULL);
20635
20636 DUK_ASSERT(h_bufobj->buf_prop == NULL);
20637 h_bufobj->buf_prop = (duk_hobject *) h_arrbuf;
20638 DUK_HBUFOBJ_INCREF(thr, h_arrbuf); /* Now reachable and accounted for. */
20639
20640 duk_pop(ctx);
20641 }
20642
20643 return;
20644
20645 range_error:
20646 DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARGS);
20647 return; /* not reached */
20648
20649 arg_error:
20650 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_ARGS);
20651 return; /* not reached */
20652}
20653#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
20654DUK_EXTERNAL void duk_push_buffer_object(duk_context *ctx, duk_idx_t idx_buffer, duk_size_t byte_offset, duk_size_t byte_length, duk_uint_t flags) {
20655 DUK_UNREF(idx_buffer);
20656 DUK_UNREF(byte_offset);
20657 DUK_UNREF(byte_length);
20658 DUK_UNREF(flags);
20659 DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx);
20660}
20661#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
20662
20663DUK_EXTERNAL duk_idx_t duk_push_error_object_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap) {
20664 duk_hthread *thr = (duk_hthread *) ctx;
20665 duk_hobject *proto;
20666#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
20667 duk_bool_t noblame_fileline;
20668#endif
20669
20670 DUK_ASSERT_CTX_VALID(ctx);
20671 DUK_ASSERT(thr != NULL);
20672 DUK_UNREF(filename);
20673 DUK_UNREF(line);
20674
20675 /* Error code also packs a tracedata related flag. */
20676#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
20677 noblame_fileline = err_code & DUK_ERRCODE_FLAG_NOBLAME_FILELINE;
20678#endif
20679 err_code = err_code & (~DUK_ERRCODE_FLAG_NOBLAME_FILELINE);
20680
20681 /* error gets its 'name' from the prototype */
20682 proto = duk_error_prototype_from_code(thr, err_code);
20683 (void) duk_push_object_helper_proto(ctx,
20684 DUK_HOBJECT_FLAG_EXTENSIBLE |
20685 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR),
20686 proto);
20687
20688 /* ... and its 'message' from an instance property */
20689 if (fmt) {
20690 duk_push_vsprintf(ctx, fmt, ap);
20691 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
20692 } else {
20693 /* If no explicit message given, put error code into message field
20694 * (as a number). This is not fully in keeping with the Ecmascript
20695 * error model because messages are supposed to be strings (Error
20696 * constructors use ToString() on their argument). However, it's
20697 * probably more useful than having a separate 'code' property.
20698 */
20699 duk_push_int(ctx, err_code);
20700 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
20701 }
20702
20703 /* XXX: .code = err_code disabled, not sure if useful */
20704
20705 /* Creation time error augmentation */
20706#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
20707 /* filename may be NULL in which case file/line is not recorded */
20708 duk_err_augment_error_create(thr, thr, filename, line, noblame_fileline); /* may throw an error */
20709#endif
20710
20711 return duk_get_top_index_unsafe(ctx);
20712}
20713
20714DUK_EXTERNAL duk_idx_t duk_push_error_object_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) {
20715 va_list ap;
20716 duk_idx_t ret;
20717
20718 DUK_ASSERT_CTX_VALID(ctx);
20719
20720 va_start(ap, fmt);
20721 ret = duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
20722 va_end(ap);
20723 return ret;
20724}
20725
20726#if !defined(DUK_USE_VARIADIC_MACROS)
20727DUK_EXTERNAL duk_idx_t duk_push_error_object_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...) {
20728 const char *filename = duk_api_global_filename;
20729 duk_int_t line = duk_api_global_line;
20730 va_list ap;
20731 duk_idx_t ret;
20732
20733 DUK_ASSERT_CTX_VALID(ctx);
20734
20735 duk_api_global_filename = NULL;
20736 duk_api_global_line = 0;
20737 va_start(ap, fmt);
20738 ret = duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
20739 va_end(ap);
20740 return ret;
20741}
20742#endif /* DUK_USE_VARIADIC_MACROS */
20743
20744DUK_EXTERNAL void *duk_push_buffer_raw(duk_context *ctx, duk_size_t size, duk_small_uint_t flags) {
20745 duk_hthread *thr = (duk_hthread *) ctx;
20746 duk_tval *tv_slot;
20747 duk_hbuffer *h;
20748 void *buf_data;
20749
20750 DUK_ASSERT_CTX_VALID(ctx);
20751
20752 /* check stack first */
20753 if (thr->valstack_top >= thr->valstack_end) {
20754 DUK_ERROR_RANGE_PUSH_BEYOND(thr);
20755 }
20756
20757 /* Check for maximum buffer length. */
20758 if (size > DUK_HBUFFER_MAX_BYTELEN) {
20759 DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG);
20760 }
20761
20762 h = duk_hbuffer_alloc(thr->heap, size, flags, &buf_data);
20763 if (!h) {
20764 DUK_ERROR_ALLOC_FAILED(thr);
20765 }
20766
20767 tv_slot = thr->valstack_top;
20768 DUK_TVAL_SET_BUFFER(tv_slot, h);
20769 DUK_HBUFFER_INCREF(thr, h);
20770 thr->valstack_top++;
20771
20772 return (void *) buf_data;
20773}
20774
20775DUK_INTERNAL void *duk_push_fixed_buffer_nozero(duk_context *ctx, duk_size_t len) {
20776 return duk_push_buffer_raw(ctx, len, DUK_BUF_FLAG_NOZERO);
20777}
20778
20779DUK_INTERNAL void *duk_push_fixed_buffer_zero(duk_context *ctx, duk_size_t len) {
20780 void *ptr;
20781 ptr = duk_push_buffer_raw(ctx, len, 0);
20782#if !defined(DUK_USE_ZERO_BUFFER_DATA)
20783 /* ES2015 requires zeroing even when DUK_USE_ZERO_BUFFER_DATA
20784 * is not set.
20785 */
20786 DUK_MEMZERO((void *) ptr, (size_t) len);
20787#endif
20788 return ptr;
20789}
20790
20791DUK_EXTERNAL duk_idx_t duk_push_heapptr(duk_context *ctx, void *ptr) {
20792 duk_hthread *thr = (duk_hthread *) ctx;
20793 duk_idx_t ret;
20794
20795 DUK_ASSERT_CTX_VALID(ctx);
20796
20797 /* Reviving an object using a heap pointer is a dangerous API
20798 * operation: if the application doesn't guarantee that the
20799 * pointer target is always reachable, difficult-to-diagnose
20800 * problems may ensue. Try to validate the 'ptr' argument to
20801 * the extent possible.
20802 */
20803
20804#if defined(DUK_USE_ASSERTIONS)
20805 {
20806 /* One particular problem case is where an object has been
20807 * queued for finalization but the finalizer hasn't been
20808 * executed.
20809 */
20810 duk_heaphdr *curr;
20811 for (curr = thr->heap->finalize_list;
20812 curr != NULL;
20813 curr = DUK_HEAPHDR_GET_NEXT(thr->heap, curr)) {
20814 DUK_ASSERT(curr != (duk_heaphdr *) ptr);
20815 }
20816 }
20817#endif
20818
20819 ret = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
20820
20821 if (ptr == NULL) {
20822 goto push_undefined;
20823 }
20824
20825 switch (DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) ptr)) {
20826 case DUK_HTYPE_STRING:
20827 duk_push_hstring(ctx, (duk_hstring *) ptr);
20828 break;
20829 case DUK_HTYPE_OBJECT:
20830 duk_push_hobject(ctx, (duk_hobject *) ptr);
20831 break;
20832 case DUK_HTYPE_BUFFER:
20833 duk_push_hbuffer(ctx, (duk_hbuffer *) ptr);
20834 break;
20835 default:
20836 goto push_undefined;
20837 }
20838 return ret;
20839
20840 push_undefined:
20841 duk_push_undefined(ctx);
20842 return ret;
20843}
20844
20845/* Push object with no prototype, i.e. a "bare" object. */
20846DUK_EXTERNAL duk_idx_t duk_push_bare_object(duk_context *ctx) {
20847 (void) duk_push_object_helper(ctx,
20848 DUK_HOBJECT_FLAG_EXTENSIBLE |
20849 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
20850 -1); /* no prototype */
20851 return duk_get_top_index_unsafe(ctx);
20852}
20853
20854DUK_INTERNAL void duk_push_hstring(duk_context *ctx, duk_hstring *h) {
20855 duk_tval tv;
20856 DUK_ASSERT_CTX_VALID(ctx);
20857 DUK_ASSERT(h != NULL);
20858 DUK_TVAL_SET_STRING(&tv, h);
20859 duk_push_tval(ctx, &tv);
20860}
20861
20862DUK_INTERNAL void duk_push_hstring_stridx(duk_context *ctx, duk_small_uint_t stridx) {
20863 duk_hthread *thr = (duk_hthread *) ctx;
20864 DUK_UNREF(thr);
20865 DUK_ASSERT_STRIDX_VALID(stridx);
20866 duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, stridx));
20867}
20868
20869DUK_INTERNAL void duk_push_hstring_empty(duk_context *ctx) {
20870 duk_hthread *thr = (duk_hthread *) ctx;
20871 DUK_UNREF(thr);
20872 duk_push_hstring(ctx, DUK_HTHREAD_GET_STRING(thr, DUK_STRIDX_EMPTY_STRING));
20873}
20874
20875DUK_INTERNAL void duk_push_hobject(duk_context *ctx, duk_hobject *h) {
20876 duk_tval tv;
20877 DUK_ASSERT_CTX_VALID(ctx);
20878 DUK_ASSERT(h != NULL);
20879 DUK_TVAL_SET_OBJECT(&tv, h);
20880 duk_push_tval(ctx, &tv);
20881}
20882
20883DUK_INTERNAL void duk_push_hbuffer(duk_context *ctx, duk_hbuffer *h) {
20884 duk_tval tv;
20885 DUK_ASSERT_CTX_VALID(ctx);
20886 DUK_ASSERT(h != NULL);
20887 DUK_TVAL_SET_BUFFER(&tv, h);
20888 duk_push_tval(ctx, &tv);
20889}
20890
20891DUK_INTERNAL void duk_push_hobject_bidx(duk_context *ctx, duk_small_int_t builtin_idx) {
20892 duk_hthread *thr = (duk_hthread *) ctx;
20893 DUK_ASSERT_CTX_VALID(ctx);
20894 DUK_ASSERT(thr != NULL);
20895 DUK_ASSERT(builtin_idx >= 0 && builtin_idx < DUK_NUM_BUILTINS);
20896 DUK_ASSERT(thr->builtins[builtin_idx] != NULL);
20897 duk_push_hobject(ctx, thr->builtins[builtin_idx]);
20898}
20899
20900/*
20901 * Poppers
20902 */
20903
20904DUK_EXTERNAL void duk_pop_n(duk_context *ctx, duk_idx_t count) {
20905 duk_hthread *thr = (duk_hthread *) ctx;
20906 duk_tval *tv;
20907#if defined(DUK_USE_REFERENCE_COUNTING)
20908 duk_tval *tv_end;
20909#endif
20910
20911 DUK_ASSERT_CTX_VALID(ctx);
20912
20913 if (DUK_UNLIKELY(count < 0)) {
20914 DUK_ERROR_RANGE_INVALID_COUNT(thr);
20915 return;
20916 }
20917
20918 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
20919 if (DUK_UNLIKELY((duk_size_t) (thr->valstack_top - thr->valstack_bottom) < (duk_size_t) count)) {
20920 DUK_ERROR_RANGE_INVALID_COUNT(thr);
20921 }
20922
20923 /*
20924 * Must be very careful here, every DECREF may cause reallocation
20925 * of our valstack.
20926 */
20927
20928 /* XXX: inlined DECREF macro would be nice here: no NULL check,
20929 * refzero queueing but no refzero algorithm run (= no pointer
20930 * instability), inline code.
20931 */
20932
20933 /* XXX: optimize loops */
20934
20935#if defined(DUK_USE_REFERENCE_COUNTING)
20936 tv = thr->valstack_top;
20937 tv_end = tv - count;
20938 while (tv != tv_end) {
20939 tv--;
20940 DUK_ASSERT(tv >= thr->valstack_bottom);
20941 DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv);
20942 }
20943 thr->valstack_top = tv;
20944 DUK_REFZERO_CHECK_FAST(thr);
20945#else
20946 tv = thr->valstack_top;
20947 while (count > 0) {
20948 count--;
20949 tv--;
20950 DUK_ASSERT(tv >= thr->valstack_bottom);
20951 DUK_TVAL_SET_UNDEFINED(tv);
20952 }
20953 thr->valstack_top = tv;
20954#endif
20955
20956 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
20957}
20958
20959/* Popping one element is called so often that when footprint is not an issue,
20960 * compile a specialized function for it.
20961 */
20962#if defined(DUK_USE_PREFER_SIZE)
20963DUK_EXTERNAL void duk_pop(duk_context *ctx) {
20964 DUK_ASSERT_CTX_VALID(ctx);
20965 duk_pop_n(ctx, 1);
20966}
20967#else
20968DUK_EXTERNAL void duk_pop(duk_context *ctx) {
20969 duk_hthread *thr = (duk_hthread *) ctx;
20970 duk_tval *tv;
20971 DUK_ASSERT_CTX_VALID(ctx);
20972
20973 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
20974 if (DUK_UNLIKELY(thr->valstack_top == thr->valstack_bottom)) {
20975 DUK_ERROR_RANGE_INVALID_COUNT(thr);
20976 }
20977
20978 tv = --thr->valstack_top; /* tv points to element just below prev top */
20979 DUK_ASSERT(tv >= thr->valstack_bottom);
20980#if defined(DUK_USE_REFERENCE_COUNTING)
20981 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
20982#else
20983 DUK_TVAL_SET_UNDEFINED(tv);
20984#endif
20985 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
20986}
20987#endif /* !DUK_USE_PREFER_SIZE */
20988
20989/* Unsafe internal variant which assumes there are enough values on the value
20990 * stack so that a top check can be skipped safely.
20991 */
20992#if defined(DUK_USE_PREFER_SIZE)
20993DUK_INTERNAL void duk_pop_unsafe(duk_context *ctx) {
20994 DUK_ASSERT_CTX_VALID(ctx);
20995 duk_pop_n(ctx, 1);
20996}
20997#else
20998DUK_INTERNAL void duk_pop_unsafe(duk_context *ctx) {
20999 duk_hthread *thr = (duk_hthread *) ctx;
21000 duk_tval *tv;
21001 DUK_ASSERT_CTX_VALID(ctx);
21002
21003 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
21004 DUK_ASSERT(thr->valstack_top != thr->valstack_bottom);
21005
21006 tv = --thr->valstack_top; /* tv points to element just below prev top */
21007 DUK_ASSERT(tv >= thr->valstack_bottom);
21008#if defined(DUK_USE_REFERENCE_COUNTING)
21009 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv); /* side effects */
21010#else
21011 DUK_TVAL_SET_UNDEFINED(tv);
21012#endif
21013 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
21014}
21015#endif /* !DUK_USE_PREFER_SIZE */
21016
21017DUK_EXTERNAL void duk_pop_2(duk_context *ctx) {
21018 DUK_ASSERT_CTX_VALID(ctx);
21019 duk_pop_n(ctx, 2);
21020}
21021
21022DUK_EXTERNAL void duk_pop_3(duk_context *ctx) {
21023 DUK_ASSERT_CTX_VALID(ctx);
21024 duk_pop_n(ctx, 3);
21025}
21026
21027/*
21028 * Pack and unpack (pack value stack entries into an array and vice versa)
21029 */
21030
21031/* XXX: pack index range? array index offset? */
21032DUK_INTERNAL void duk_pack(duk_context *ctx, duk_idx_t count) {
21033 duk_hthread *thr;
21034 duk_harray *a;
21035 duk_tval *tv_src;
21036 duk_tval *tv_dst;
21037 duk_tval *tv_curr;
21038 duk_tval *tv_limit;
21039 duk_idx_t top;
21040
21041 DUK_ASSERT_CTX_VALID(ctx);
21042 thr = (duk_hthread *) ctx;
21043
21044 top = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
21045 if (count < 0 || count > top) {
21046 DUK_ERROR_RANGE_INVALID_COUNT(thr);
21047 return;
21048 }
21049
21050 /* Wrapping is controlled by the check above: value stack top can be
21051 * at most thr->valstack_max which is low enough so that multiplying
21052 * with sizeof(duk_tval) won't wrap.
21053 */
21054 DUK_ASSERT(count >= 0 && count <= (duk_idx_t) thr->valstack_max);
21055 DUK_ASSERT((duk_size_t) count <= DUK_SIZE_MAX / sizeof(duk_tval)); /* no wrapping */
21056
21057 a = duk_push_harray_with_size(ctx, (duk_uint32_t) count); /* XXX: uninitialized would be OK */
21058 DUK_ASSERT(a != NULL);
21059 DUK_ASSERT(DUK_HOBJECT_GET_ASIZE((duk_hobject *) a) == (duk_uint32_t) count);
21060 DUK_ASSERT(count == 0 || DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a) != NULL);
21061 DUK_ASSERT((duk_idx_t) a->length == count);
21062
21063 /* Copy value stack values directly to the array part without
21064 * any refcount updates: net refcount changes are zero.
21065 */
21066
21067 tv_src = thr->valstack_top - count - 1;
21068 tv_dst = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a);
21069 DUK_MEMCPY((void *) tv_dst, (const void *) tv_src, (size_t) count * sizeof(duk_tval));
21070
21071 /* Overwrite result array to final value stack location and wipe
21072 * the rest; no refcount operations needed.
21073 */
21074
21075 tv_dst = tv_src; /* when count == 0, same as tv_src (OK) */
21076 tv_src = thr->valstack_top - 1;
21077 DUK_TVAL_SET_TVAL(tv_dst, tv_src);
21078
21079 /* XXX: internal helper to wipe a value stack segment? */
21080 tv_curr = tv_dst + 1;
21081 tv_limit = thr->valstack_top;
21082 while (tv_curr != tv_limit) {
21083 /* Wipe policy: keep as 'undefined'. */
21084 DUK_TVAL_SET_UNDEFINED(tv_curr);
21085 tv_curr++;
21086 }
21087 thr->valstack_top = tv_dst + 1;
21088}
21089
21090#if 0
21091/* XXX: unpack to position? */
21092DUK_INTERNAL void duk_unpack(duk_context *ctx) {
21093 /* - dense with length <= a_part
21094 * - dense with length > a_part
21095 * - sparse
21096 * - array-like but not actually an array?
21097 * - how to deal with 'unused' values (gaps); inherit or ignore?
21098 */
21099}
21100#endif
21101
21102/*
21103 * Error throwing
21104 */
21105
21106DUK_EXTERNAL void duk_throw_raw(duk_context *ctx) {
21107 duk_hthread *thr = (duk_hthread *) ctx;
21108
21109 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
21110 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
21111 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
21112
21113 if (thr->valstack_top == thr->valstack_bottom) {
21114 DUK_ERROR_TYPE_INVALID_ARGS(thr);
21115 }
21116
21117 /* Errors are augmented when they are created, not when they are
21118 * thrown or re-thrown. The current error handler, however, runs
21119 * just before an error is thrown.
21120 */
21121
21122 /* Sync so that augmentation sees up-to-date activations, NULL
21123 * thr->ptr_curr_pc so that it's not used if side effects occur
21124 * in augmentation or longjmp handling.
21125 */
21126 duk_hthread_sync_and_null_currpc(thr);
21127
21128#if defined(DUK_USE_AUGMENT_ERROR_THROW)
21129 DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (before throw augment)", (duk_tval *) duk_get_tval(ctx, -1)));
21130 duk_err_augment_error_throw(thr);
21131#endif
21132 DUK_DDD(DUK_DDDPRINT("THROW ERROR (API): %!dT (after throw augment)", (duk_tval *) duk_get_tval(ctx, -1)));
21133
21134 duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW);
21135
21136 /* thr->heap->lj.jmpbuf_ptr is checked by duk_err_longjmp() so we don't
21137 * need to check that here. If the value is NULL, a fatal error occurs
21138 * because we can't return.
21139 */
21140
21141 duk_err_longjmp(thr);
21142 DUK_UNREACHABLE();
21143}
21144
21145DUK_EXTERNAL void duk_fatal_raw(duk_context *ctx, const char *err_msg) {
21146 duk_hthread *thr = (duk_hthread *) ctx;
21147
21148 DUK_ASSERT_CTX_VALID(ctx);
21149 DUK_ASSERT(thr != NULL);
21150 DUK_ASSERT(thr->heap != NULL);
21151 DUK_ASSERT(thr->heap->fatal_func != NULL);
21152
21153 DUK_D(DUK_DPRINT("fatal error occurred: %s", err_msg ? err_msg : "NULL"));
21154
21155 /* fatal_func should be noreturn, but noreturn declarations on function
21156 * pointers has a very spotty support apparently so it's not currently
21157 * done.
21158 */
21159 thr->heap->fatal_func(thr->heap->heap_udata, err_msg);
21160
21161 /* If the fatal handler returns, all bets are off. It'd be nice to
21162 * print something here but since we don't want to depend on stdio,
21163 * there's no way to do so portably.
21164 */
21165 DUK_D(DUK_DPRINT("fatal error handler returned, all bets are off!"));
21166 for (;;) {
21167 /* loop forever, don't return (function marked noreturn) */
21168 }
21169}
21170
21171DUK_EXTERNAL void duk_error_va_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, va_list ap) {
21172 DUK_ASSERT_CTX_VALID(ctx);
21173
21174 duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
21175 (void) duk_throw(ctx);
21176}
21177
21178DUK_EXTERNAL void duk_error_raw(duk_context *ctx, duk_errcode_t err_code, const char *filename, duk_int_t line, const char *fmt, ...) {
21179 va_list ap;
21180
21181 DUK_ASSERT_CTX_VALID(ctx);
21182
21183 va_start(ap, fmt);
21184 duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
21185 va_end(ap);
21186 (void) duk_throw(ctx);
21187}
21188
21189#if !defined(DUK_USE_VARIADIC_MACROS)
21190DUK_NORETURN(DUK_LOCAL_DECL void duk__throw_error_from_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, va_list ap));
21191
21192DUK_LOCAL void duk__throw_error_from_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, va_list ap) {
21193 const char *filename;
21194 duk_int_t line;
21195
21196 DUK_ASSERT_CTX_VALID(ctx);
21197
21198 filename = duk_api_global_filename;
21199 line = duk_api_global_line;
21200 duk_api_global_filename = NULL;
21201 duk_api_global_line = 0;
21202
21203 duk_push_error_object_va_raw(ctx, err_code, filename, line, fmt, ap);
21204 (void) duk_throw(ctx);
21205}
21206
21207#define DUK__ERROR_STASH_SHARED(code) do { \
21208 va_list ap; \
21209 va_start(ap, fmt); \
21210 duk__throw_error_from_stash(ctx, (code), fmt, ap); \
21211 va_end(ap); \
21212 /* Never reached; if return 0 here, gcc/clang will complain. */ \
21213 } while (0)
21214
21215DUK_EXTERNAL duk_ret_t duk_error_stash(duk_context *ctx, duk_errcode_t err_code, const char *fmt, ...) {
21216 DUK__ERROR_STASH_SHARED(err_code);
21217}
21218DUK_EXTERNAL duk_ret_t duk_generic_error_stash(duk_context *ctx, const char *fmt, ...) {
21219 DUK__ERROR_STASH_SHARED(DUK_ERR_ERROR);
21220}
21221DUK_EXTERNAL duk_ret_t duk_eval_error_stash(duk_context *ctx, const char *fmt, ...) {
21222 DUK__ERROR_STASH_SHARED(DUK_ERR_EVAL_ERROR);
21223}
21224DUK_EXTERNAL duk_ret_t duk_range_error_stash(duk_context *ctx, const char *fmt, ...) {
21225 DUK__ERROR_STASH_SHARED(DUK_ERR_RANGE_ERROR);
21226}
21227DUK_EXTERNAL duk_ret_t duk_reference_error_stash(duk_context *ctx, const char *fmt, ...) {
21228 DUK__ERROR_STASH_SHARED(DUK_ERR_REFERENCE_ERROR);
21229}
21230DUK_EXTERNAL duk_ret_t duk_syntax_error_stash(duk_context *ctx, const char *fmt, ...) {
21231 DUK__ERROR_STASH_SHARED(DUK_ERR_SYNTAX_ERROR);
21232}
21233DUK_EXTERNAL duk_ret_t duk_type_error_stash(duk_context *ctx, const char *fmt, ...) {
21234 DUK__ERROR_STASH_SHARED(DUK_ERR_TYPE_ERROR);
21235}
21236DUK_EXTERNAL duk_ret_t duk_uri_error_stash(duk_context *ctx, const char *fmt, ...) {
21237 DUK__ERROR_STASH_SHARED(DUK_ERR_URI_ERROR);
21238}
21239#endif /* DUK_USE_VARIADIC_MACROS */
21240
21241/*
21242 * Comparison
21243 */
21244
21245DUK_EXTERNAL duk_bool_t duk_equals(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2) {
21246 duk_hthread *thr = (duk_hthread *) ctx;
21247 duk_tval *tv1, *tv2;
21248
21249 DUK_ASSERT_CTX_VALID(ctx);
21250
21251 tv1 = duk_get_tval(ctx, idx1);
21252 tv2 = duk_get_tval(ctx, idx2);
21253 if ((tv1 == NULL) || (tv2 == NULL)) {
21254 return 0;
21255 }
21256
21257 /* Coercion may be needed, the helper handles that by pushing the
21258 * tagged values to the stack.
21259 */
21260 return duk_js_equals(thr, tv1, tv2);
21261}
21262
21263DUK_EXTERNAL duk_bool_t duk_strict_equals(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2) {
21264 duk_tval *tv1, *tv2;
21265
21266 DUK_ASSERT_CTX_VALID(ctx);
21267
21268 tv1 = duk_get_tval(ctx, idx1);
21269 tv2 = duk_get_tval(ctx, idx2);
21270 if ((tv1 == NULL) || (tv2 == NULL)) {
21271 return 0;
21272 }
21273
21274 /* No coercions or other side effects, so safe */
21275 return duk_js_strict_equals(tv1, tv2);
21276}
21277
21278DUK_EXTERNAL_DECL duk_bool_t duk_samevalue(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2) {
21279 duk_tval *tv1, *tv2;
21280
21281 DUK_ASSERT_CTX_VALID(ctx);
21282
21283 tv1 = duk_get_tval(ctx, idx1);
21284 tv2 = duk_get_tval(ctx, idx2);
21285 if ((tv1 == NULL) || (tv2 == NULL)) {
21286 return 0;
21287 }
21288
21289 /* No coercions or other side effects, so safe */
21290 return duk_js_samevalue(tv1, tv2);
21291}
21292
21293/*
21294 * instanceof
21295 */
21296
21297DUK_EXTERNAL duk_bool_t duk_instanceof(duk_context *ctx, duk_idx_t idx1, duk_idx_t idx2) {
21298 duk_tval *tv1, *tv2;
21299
21300 DUK_ASSERT_CTX_VALID(ctx);
21301
21302 /* Index validation is strict, which differs from duk_equals().
21303 * The strict behavior mimics how instanceof itself works, e.g.
21304 * it is a TypeError if rval is not a -callable- object. It would
21305 * be somewhat inconsistent if rval would be allowed to be
21306 * non-existent without a TypeError.
21307 */
21308 tv1 = duk_require_tval(ctx, idx1);
21309 DUK_ASSERT(tv1 != NULL);
21310 tv2 = duk_require_tval(ctx, idx2);
21311 DUK_ASSERT(tv2 != NULL);
21312
21313 return duk_js_instanceof((duk_hthread *) ctx, tv1, tv2);
21314}
21315
21316/*
21317 * Lightfunc
21318 */
21319
21320DUK_INTERNAL void duk_push_lightfunc_name_raw(duk_context *ctx, duk_c_function func, duk_small_uint_t lf_flags) {
21321 /* Lightfunc name, includes Duktape/C native function pointer, which
21322 * can often be used to locate the function from a symbol table.
21323 * The name also includes the 16-bit duk_tval flags field because it
21324 * includes the magic value. Because a single native function often
21325 * provides different functionality depending on the magic value, it
21326 * seems reasonably to include it in the name.
21327 *
21328 * On the other hand, a complicated name increases string table
21329 * pressure in low memory environments (but only when function name
21330 * is accessed).
21331 */
21332
21333 duk_push_sprintf(ctx, "light_");
21334 duk_push_string_funcptr(ctx, (duk_uint8_t *) &func, sizeof(func));
21335 duk_push_sprintf(ctx, "_%04x", (unsigned int) lf_flags);
21336 duk_concat(ctx, 3);
21337}
21338
21339DUK_INTERNAL void duk_push_lightfunc_name(duk_context *ctx, duk_tval *tv) {
21340 duk_c_function func;
21341 duk_small_uint_t lf_flags;
21342
21343 DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv));
21344 DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags);
21345 duk_push_lightfunc_name_raw(ctx, func, lf_flags);
21346}
21347
21348DUK_INTERNAL void duk_push_lightfunc_tostring(duk_context *ctx, duk_tval *tv) {
21349 duk_c_function func;
21350 duk_small_uint_t lf_flags;
21351
21352 DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv));
21353 DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags); /* read before 'tv' potentially invalidated */
21354
21355 duk_push_string(ctx, "function ");
21356 duk_push_lightfunc_name_raw(ctx, func, lf_flags);
21357 duk_push_string(ctx, "() { [lightfunc code] }");
21358 duk_concat(ctx, 3);
21359}
21360
21361/*
21362 * Function pointers
21363 *
21364 * Printing function pointers is non-portable, so we do that by hex printing
21365 * bytes from memory.
21366 */
21367
21368DUK_INTERNAL void duk_push_string_funcptr(duk_context *ctx, duk_uint8_t *ptr, duk_size_t sz) {
21369 duk_uint8_t buf[32 * 2];
21370 duk_uint8_t *p, *q;
21371 duk_small_uint_t i;
21372 duk_small_uint_t t;
21373
21374 DUK_ASSERT(sz <= 32); /* sanity limit for function pointer size */
21375
21376 p = buf;
21377#if defined(DUK_USE_INTEGER_LE)
21378 q = ptr + sz;
21379#else
21380 q = ptr;
21381#endif
21382 for (i = 0; i < sz; i++) {
21383#if defined(DUK_USE_INTEGER_LE)
21384 t = *(--q);
21385#else
21386 t = *(q++);
21387#endif
21388 *p++ = duk_lc_digits[t >> 4];
21389 *p++ = duk_lc_digits[t & 0x0f];
21390 }
21391
21392 duk_push_lstring(ctx, (const char *) buf, sz * 2);
21393}
21394
21395/*
21396 * Push readable string summarizing duk_tval. The operation is side effect
21397 * free and will only throw from internal errors (e.g. out of memory).
21398 * This is used by e.g. property access code to summarize a key/base safely,
21399 * and is not intended to be fast (but small and safe).
21400 */
21401
21402#define DUK__READABLE_STRING_MAXCHARS 32
21403
21404/* String sanitizer which escapes ASCII control characters and a few other
21405 * ASCII characters, passes Unicode as is, and replaces invalid UTF-8 with
21406 * question marks. No errors are thrown for any input string, except in out
21407 * of memory situations.
21408 */
21409DUK_LOCAL void duk__push_hstring_readable_unicode(duk_context *ctx, duk_hstring *h_input) {
21410 duk_hthread *thr;
21411 const duk_uint8_t *p, *p_start, *p_end;
21412 duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH * DUK__READABLE_STRING_MAXCHARS +
21413 2 /*quotes*/ + 3 /*periods*/];
21414 duk_uint8_t *q;
21415 duk_ucodepoint_t cp;
21416 duk_small_uint_t nchars;
21417
21418 DUK_ASSERT_CTX_VALID(ctx);
21419 DUK_ASSERT(h_input != NULL);
21420 thr = (duk_hthread *) ctx;
21421
21422 p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
21423 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
21424 p = p_start;
21425 q = buf;
21426
21427 nchars = 0;
21428 *q++ = (duk_uint8_t) DUK_ASC_SINGLEQUOTE;
21429 for (;;) {
21430 if (p >= p_end) {
21431 break;
21432 }
21433 if (nchars == DUK__READABLE_STRING_MAXCHARS) {
21434 *q++ = (duk_uint8_t) DUK_ASC_PERIOD;
21435 *q++ = (duk_uint8_t) DUK_ASC_PERIOD;
21436 *q++ = (duk_uint8_t) DUK_ASC_PERIOD;
21437 break;
21438 }
21439 if (duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp)) {
21440 if (cp < 0x20 || cp == 0x7f || cp == DUK_ASC_SINGLEQUOTE || cp == DUK_ASC_BACKSLASH) {
21441 DUK_ASSERT(DUK_UNICODE_MAX_XUTF8_LENGTH >= 4); /* estimate is valid */
21442 DUK_ASSERT((cp >> 4) <= 0x0f);
21443 *q++ = (duk_uint8_t) DUK_ASC_BACKSLASH;
21444 *q++ = (duk_uint8_t) DUK_ASC_LC_X;
21445 *q++ = (duk_uint8_t) duk_lc_digits[cp >> 4];
21446 *q++ = (duk_uint8_t) duk_lc_digits[cp & 0x0f];
21447 } else {
21448 q += duk_unicode_encode_xutf8(cp, q);
21449 }
21450 } else {
21451 p++; /* advance manually */
21452 *q++ = (duk_uint8_t) DUK_ASC_QUESTION;
21453 }
21454 nchars++;
21455 }
21456 *q++ = (duk_uint8_t) DUK_ASC_SINGLEQUOTE;
21457
21458 duk_push_lstring(ctx, (const char *) buf, (duk_size_t) (q - buf));
21459}
21460
21461DUK_LOCAL const char *duk__push_string_tval_readable(duk_context *ctx, duk_tval *tv, duk_bool_t error_aware) {
21462 duk_hthread *thr;
21463
21464 DUK_ASSERT_CTX_VALID(ctx);
21465 thr = (duk_hthread *) ctx;
21466 DUK_UNREF(thr);
21467 /* 'tv' may be NULL */
21468
21469 if (tv == NULL) {
21470 duk_push_string(ctx, "none");
21471 } else {
21472 switch (DUK_TVAL_GET_TAG(tv)) {
21473 case DUK_TAG_STRING: {
21474 /* XXX: symbol support (maybe in summary rework branch) */
21475 duk__push_hstring_readable_unicode(ctx, DUK_TVAL_GET_STRING(tv));
21476 break;
21477 }
21478 case DUK_TAG_OBJECT: {
21479 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
21480 DUK_ASSERT(h != NULL);
21481
21482 if (error_aware &&
21483 duk_hobject_prototype_chain_contains(thr, h, thr->builtins[DUK_BIDX_ERROR_PROTOTYPE], 1 /*ignore_loop*/)) {
21484 /* Get error message in a side effect free way if
21485 * possible; if not, summarize as a generic object.
21486 * Error message currently gets quoted.
21487 */
21488 /* XXX: better internal getprop call; get without side effects
21489 * but traverse inheritance chain.
21490 */
21491 duk_tval *tv_msg;
21492 tv_msg = duk_hobject_find_existing_entry_tval_ptr(thr->heap, h, DUK_HTHREAD_STRING_MESSAGE(thr));
21493 if (tv_msg) {
21494 /* It's important this summarization is
21495 * not error aware to avoid unlimited
21496 * recursion when the .message property
21497 * is e.g. another error.
21498 */
21499 return duk_push_string_tval_readable(ctx, tv_msg);
21500 }
21501 }
21502 duk_push_class_string_tval(ctx, tv);
21503 break;
21504 }
21505 case DUK_TAG_BUFFER: {
21506 /* While plain buffers mimic Uint8Arrays, they summarize differently.
21507 * This is useful so that the summarized string accurately reflects the
21508 * internal type which may matter for figuring out bugs etc.
21509 */
21510 /* XXX: Hex encoded, length limited buffer summary here? */
21511 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv);
21512 DUK_ASSERT(h != NULL);
21513 duk_push_sprintf(ctx, "[buffer:%ld]", (long) DUK_HBUFFER_GET_SIZE(h));
21514 break;
21515 }
21516 case DUK_TAG_POINTER: {
21517 /* Surround with parentheses like in JX, ensures NULL pointer
21518 * is distinguishable from null value ("(null)" vs "null").
21519 */
21520 duk_push_tval(ctx, tv);
21521 duk_push_sprintf(ctx, "(%s)", duk_to_string(ctx, -1));
21522 duk_remove_m2(ctx);
21523 break;
21524 }
21525 default: {
21526 duk_push_tval(ctx, tv);
21527 break;
21528 }
21529 }
21530 }
21531
21532 return duk_to_string(ctx, -1);
21533}
21534DUK_INTERNAL const char *duk_push_string_tval_readable(duk_context *ctx, duk_tval *tv) {
21535 DUK_ASSERT_CTX_VALID(ctx);
21536 return duk__push_string_tval_readable(ctx, tv, 0 /*error_aware*/);
21537}
21538
21539DUK_INTERNAL const char *duk_push_string_readable(duk_context *ctx, duk_idx_t idx) {
21540 DUK_ASSERT_CTX_VALID(ctx);
21541 return duk_push_string_tval_readable(ctx, duk_get_tval(ctx, idx));
21542}
21543
21544DUK_INTERNAL const char *duk_push_string_tval_readable_error(duk_context *ctx, duk_tval *tv) {
21545 DUK_ASSERT_CTX_VALID(ctx);
21546 return duk__push_string_tval_readable(ctx, tv, 1 /*error_aware*/);
21547}
21548
21549DUK_INTERNAL void duk_push_symbol_descriptive_string(duk_context *ctx, duk_hstring *h) {
21550 const duk_uint8_t *p;
21551 const duk_uint8_t *p_end;
21552 const duk_uint8_t *q;
21553
21554 /* .toString() */
21555 duk_push_string(ctx, "Symbol(");
21556 p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
21557 p_end = p + DUK_HSTRING_GET_BYTELEN(h);
21558 DUK_ASSERT(p[0] == 0xff || (p[0] & 0xc0) == 0x80);
21559 p++;
21560 for (q = p; q < p_end; q++) {
21561 if (*q == 0xffU) {
21562 /* Terminate either at end-of-string (but NUL MUST
21563 * be accepted without terminating description) or
21564 * 0xFF, which is used to mark start of unique trailer
21565 * (and cannot occur in CESU-8 / extended UTF-8).
21566 */
21567 break;
21568 }
21569 }
21570 duk_push_lstring(ctx, (const char *) p, (duk_size_t) (q - p));
21571 duk_push_string(ctx, ")");
21572 duk_concat(ctx, 3);
21573}
21574
21575/* automatic undefs */
21576#undef DUK__CHECK_SPACE
21577#undef DUK__ERROR_STASH_SHARED
21578#undef DUK__PACK_ARGS
21579#undef DUK__READABLE_STRING_MAXCHARS
21580/*
21581 * String manipulation
21582 */
21583
21584/* #include duk_internal.h -> already included */
21585
21586DUK_LOCAL void duk__concat_and_join_helper(duk_context *ctx, duk_idx_t count_in, duk_bool_t is_join) {
21587 duk_hthread *thr = (duk_hthread *) ctx;
21588 duk_uint_t count;
21589 duk_uint_t i;
21590 duk_size_t idx;
21591 duk_size_t len;
21592 duk_hstring *h;
21593 duk_uint8_t *buf;
21594
21595 DUK_ASSERT_CTX_VALID(ctx);
21596
21597 if (DUK_UNLIKELY(count_in <= 0)) {
21598 if (count_in < 0) {
21599 DUK_ERROR_RANGE_INVALID_COUNT(thr);
21600 return;
21601 }
21602 DUK_ASSERT(count_in == 0);
21603 duk_push_hstring_empty(ctx);
21604 return;
21605 }
21606 count = (duk_uint_t) count_in;
21607
21608 if (is_join) {
21609 duk_size_t t1, t2, limit;
21610 h = duk_to_hstring(ctx, -((duk_idx_t) count) - 1);
21611 DUK_ASSERT(h != NULL);
21612
21613 /* A bit tricky overflow test, see doc/code-issues.rst. */
21614 t1 = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h);
21615 t2 = (duk_size_t) (count - 1);
21616 limit = (duk_size_t) DUK_HSTRING_MAX_BYTELEN;
21617 if (DUK_UNLIKELY(t2 != 0 && t1 > limit / t2)) {
21618 /* Combined size of separators already overflows. */
21619 goto error_overflow;
21620 }
21621 len = (duk_size_t) (t1 * t2);
21622 } else {
21623 len = (duk_size_t) 0;
21624 }
21625
21626 for (i = count; i >= 1; i--) {
21627 duk_size_t new_len;
21628 h = duk_to_hstring(ctx, -((duk_idx_t) i));
21629 new_len = len + (duk_size_t) DUK_HSTRING_GET_BYTELEN(h);
21630
21631 /* Impose a string maximum length, need to handle overflow
21632 * correctly.
21633 */
21634 if (new_len < len || /* wrapped */
21635 new_len > (duk_size_t) DUK_HSTRING_MAX_BYTELEN) {
21636 goto error_overflow;
21637 }
21638 len = new_len;
21639 }
21640
21641 DUK_DDD(DUK_DDDPRINT("join/concat %lu strings, total length %lu bytes",
21642 (unsigned long) count, (unsigned long) len));
21643
21644 /* Use stack allocated buffer to ensure reachability in errors
21645 * (e.g. intern error).
21646 */
21647 buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, len);
21648 DUK_ASSERT(buf != NULL);
21649
21650 /* [ ... (sep) str1 str2 ... strN buf ] */
21651
21652 idx = 0;
21653 for (i = count; i >= 1; i--) {
21654 if (is_join && i != count) {
21655 h = duk_require_hstring(ctx, -((duk_idx_t) count) - 2); /* extra -1 for buffer */
21656 DUK_MEMCPY(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
21657 idx += DUK_HSTRING_GET_BYTELEN(h);
21658 }
21659 h = duk_require_hstring(ctx, -((duk_idx_t) i) - 1); /* extra -1 for buffer */
21660 DUK_MEMCPY(buf + idx, DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
21661 idx += DUK_HSTRING_GET_BYTELEN(h);
21662 }
21663
21664 DUK_ASSERT(idx == len);
21665
21666 /* [ ... (sep) str1 str2 ... strN buf ] */
21667
21668 /* Get rid of the strings early to minimize memory use before intern. */
21669
21670 if (is_join) {
21671 duk_replace(ctx, -((duk_idx_t) count) - 2); /* overwrite sep */
21672 duk_pop_n(ctx, count);
21673 } else {
21674 duk_replace(ctx, -((duk_idx_t) count) - 1); /* overwrite str1 */
21675 duk_pop_n(ctx, count-1);
21676 }
21677
21678 /* [ ... buf ] */
21679
21680 (void) duk_buffer_to_string(ctx, -1); /* Safe if inputs are safe. */
21681
21682 /* [ ... res ] */
21683 return;
21684
21685 error_overflow:
21686 DUK_ERROR_RANGE(thr, DUK_STR_RESULT_TOO_LONG);
21687}
21688
21689DUK_EXTERNAL void duk_concat(duk_context *ctx, duk_idx_t count) {
21690 DUK_ASSERT_CTX_VALID(ctx);
21691
21692 duk__concat_and_join_helper(ctx, count, 0 /*is_join*/);
21693}
21694
21695DUK_EXTERNAL void duk_join(duk_context *ctx, duk_idx_t count) {
21696 DUK_ASSERT_CTX_VALID(ctx);
21697
21698 duk__concat_and_join_helper(ctx, count, 1 /*is_join*/);
21699}
21700
21701/* XXX: could map/decode be unified with duk_unicode_support.c code?
21702 * Case conversion needs also the character surroundings though.
21703 */
21704
21705DUK_EXTERNAL void duk_decode_string(duk_context *ctx, duk_idx_t idx, duk_decode_char_function callback, void *udata) {
21706 duk_hthread *thr = (duk_hthread *) ctx;
21707 duk_hstring *h_input;
21708 const duk_uint8_t *p, *p_start, *p_end;
21709 duk_codepoint_t cp;
21710
21711 DUK_ASSERT_CTX_VALID(ctx);
21712
21713 h_input = duk_require_hstring(ctx, idx); /* Accept symbols. */
21714 DUK_ASSERT(h_input != NULL);
21715
21716 p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
21717 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
21718 p = p_start;
21719
21720 for (;;) {
21721 if (p >= p_end) {
21722 break;
21723 }
21724 cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
21725 callback(udata, cp);
21726 }
21727}
21728
21729DUK_EXTERNAL void duk_map_string(duk_context *ctx, duk_idx_t idx, duk_map_char_function callback, void *udata) {
21730 duk_hthread *thr = (duk_hthread *) ctx;
21731 duk_hstring *h_input;
21732 duk_bufwriter_ctx bw_alloc;
21734 const duk_uint8_t *p, *p_start, *p_end;
21735 duk_codepoint_t cp;
21736
21737 DUK_ASSERT_CTX_VALID(ctx);
21738
21739 idx = duk_normalize_index(ctx, idx);
21740
21741 h_input = duk_require_hstring(ctx, idx); /* Accept symbols. */
21742 DUK_ASSERT(h_input != NULL);
21743
21744 bw = &bw_alloc;
21745 DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); /* Reasonable output estimate. */
21746
21747 p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
21748 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
21749 p = p_start;
21750
21751 for (;;) {
21752 /* XXX: could write output in chunks with fewer ensure calls,
21753 * but relative benefit would be small here.
21754 */
21755
21756 if (p >= p_end) {
21757 break;
21758 }
21759 cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p, p_start, p_end);
21760 cp = callback(udata, cp);
21761
21762 DUK_BW_WRITE_ENSURE_XUTF8(thr, bw, cp);
21763 }
21764
21765 DUK_BW_COMPACT(thr, bw);
21766 (void) duk_buffer_to_string(ctx, -1); /* Safe, extended UTF-8 encoded. */
21767 duk_replace(ctx, idx);
21768}
21769
21770DUK_EXTERNAL void duk_substring(duk_context *ctx, duk_idx_t idx, duk_size_t start_offset, duk_size_t end_offset) {
21771 duk_hthread *thr = (duk_hthread *) ctx;
21772 duk_hstring *h;
21773 duk_hstring *res;
21774 duk_size_t start_byte_offset;
21775 duk_size_t end_byte_offset;
21776
21777 DUK_ASSERT_CTX_VALID(ctx);
21778
21779 idx = duk_require_normalize_index(ctx, idx); /* Accept symbols. */
21780 h = duk_require_hstring(ctx, idx);
21781 DUK_ASSERT(h != NULL);
21782
21783 if (end_offset >= DUK_HSTRING_GET_CHARLEN(h)) {
21784 end_offset = DUK_HSTRING_GET_CHARLEN(h);
21785 }
21786 if (start_offset > end_offset) {
21787 start_offset = end_offset;
21788 }
21789
21790 DUK_ASSERT_DISABLE(start_offset >= 0);
21791 DUK_ASSERT(start_offset <= end_offset && start_offset <= DUK_HSTRING_GET_CHARLEN(h));
21792 DUK_ASSERT_DISABLE(end_offset >= 0);
21793 DUK_ASSERT(end_offset >= start_offset && end_offset <= DUK_HSTRING_GET_CHARLEN(h));
21794
21795 /* Guaranteed by string limits. */
21796 DUK_ASSERT(start_offset <= DUK_UINT32_MAX);
21797 DUK_ASSERT(end_offset <= DUK_UINT32_MAX);
21798
21799 start_byte_offset = (duk_size_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) start_offset);
21800 end_byte_offset = (duk_size_t) duk_heap_strcache_offset_char2byte(thr, h, (duk_uint_fast32_t) end_offset);
21801
21802 DUK_ASSERT(end_byte_offset >= start_byte_offset);
21803 DUK_ASSERT(end_byte_offset - start_byte_offset <= DUK_UINT32_MAX); /* Guaranteed by string limits. */
21804
21805 /* No size check is necessary. */
21806 res = duk_heap_string_intern_checked(thr,
21807 DUK_HSTRING_GET_DATA(h) + start_byte_offset,
21808 (duk_uint32_t) (end_byte_offset - start_byte_offset));
21809
21810 duk_push_hstring(ctx, res);
21811 duk_replace(ctx, idx);
21812}
21813
21814/* XXX: this is quite clunky. Add Unicode helpers to scan backwards and
21815 * forwards with a callback to process codepoints?
21816 */
21817DUK_EXTERNAL void duk_trim(duk_context *ctx, duk_idx_t idx) {
21818 duk_hthread *thr = (duk_hthread *) ctx;
21819 duk_hstring *h;
21820 const duk_uint8_t *p, *p_start, *p_end, *p_tmp1, *p_tmp2; /* pointers for scanning */
21821 const duk_uint8_t *q_start, *q_end; /* start (incl) and end (excl) of trimmed part */
21822 duk_codepoint_t cp;
21823
21824 DUK_ASSERT_CTX_VALID(ctx);
21825
21826 idx = duk_require_normalize_index(ctx, idx); /* Accept symbols. */
21827 h = duk_require_hstring(ctx, idx);
21828 DUK_ASSERT(h != NULL);
21829
21830 p_start = DUK_HSTRING_GET_DATA(h);
21831 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h);
21832
21833 p = p_start;
21834 while (p < p_end) {
21835 p_tmp1 = p;
21836 cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p_tmp1, p_start, p_end);
21837 if (!(duk_unicode_is_whitespace(cp) || duk_unicode_is_line_terminator(cp))) {
21838 break;
21839 }
21840 p = p_tmp1;
21841 }
21842 q_start = p;
21843 if (p == p_end) {
21844 /* Entire string is whitespace. */
21845 q_end = p;
21846 goto scan_done;
21847 }
21848
21849 p = p_end;
21850 while (p > p_start) {
21851 p_tmp1 = p;
21852 while (p > p_start) {
21853 p--;
21854 if (((*p) & 0xc0) != 0x80) {
21855 break;
21856 }
21857 }
21858 p_tmp2 = p;
21859
21860 cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &p_tmp2, p_start, p_end);
21861 if (!(duk_unicode_is_whitespace(cp) || duk_unicode_is_line_terminator(cp))) {
21862 p = p_tmp1;
21863 break;
21864 }
21865 }
21866 q_end = p;
21867
21868 scan_done:
21869 /* This may happen when forward and backward scanning disagree
21870 * (possible for non-extended-UTF-8 strings).
21871 */
21872 if (q_end < q_start) {
21873 q_end = q_start;
21874 }
21875
21876 DUK_ASSERT(q_start >= p_start && q_start <= p_end);
21877 DUK_ASSERT(q_end >= p_start && q_end <= p_end);
21878 DUK_ASSERT(q_end >= q_start);
21879
21880 DUK_DDD(DUK_DDDPRINT("trim: p_start=%p, p_end=%p, q_start=%p, q_end=%p",
21881 (const void *) p_start, (const void *) p_end,
21882 (const void *) q_start, (const void *) q_end));
21883
21884 if (q_start == p_start && q_end == p_end) {
21885 DUK_DDD(DUK_DDDPRINT("nothing was trimmed: avoid interning (hashing etc)"));
21886 return;
21887 }
21888
21889 duk_push_lstring(ctx, (const char *) q_start, (duk_size_t) (q_end - q_start));
21890 duk_replace(ctx, idx);
21891}
21892
21893DUK_EXTERNAL duk_codepoint_t duk_char_code_at(duk_context *ctx, duk_idx_t idx, duk_size_t char_offset) {
21894 duk_hthread *thr = (duk_hthread *) ctx;
21895 duk_hstring *h;
21896 duk_ucodepoint_t cp;
21897
21898 DUK_ASSERT_CTX_VALID(ctx);
21899
21900 /* XXX: Share code with String.prototype.charCodeAt? Main difference
21901 * is handling of clamped offsets.
21902 */
21903
21904 h = duk_require_hstring(ctx, idx); /* Accept symbols. */
21905 DUK_ASSERT(h != NULL);
21906
21907 DUK_ASSERT_DISABLE(char_offset >= 0); /* Always true, arg is unsigned. */
21908 if (char_offset >= DUK_HSTRING_GET_CHARLEN(h)) {
21909 return 0;
21910 }
21911
21912 DUK_ASSERT(char_offset <= DUK_UINT_MAX); /* Guaranteed by string limits. */
21913 cp = duk_hstring_char_code_at_raw(thr, h, (duk_uint_t) char_offset, 0 /*surrogate_aware*/);
21914 return (duk_codepoint_t) cp;
21915}
21916/*
21917 * Date/time.
21918 */
21919
21920/* #include duk_internal.h -> already included */
21921
21922DUK_EXTERNAL duk_double_t duk_get_now(duk_context *ctx) {
21923 return ((duk_double_t) DUK_USE_DATE_GET_NOW((ctx)));
21924}
21925
21926DUK_EXTERNAL void duk_time_to_components(duk_context *ctx, duk_double_t timeval, duk_time_components *comp) {
21927 duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
21928 duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
21929 duk_uint_t flags;
21930
21931 DUK_ASSERT(ctx != NULL);
21932 DUK_ASSERT(comp != NULL); /* XXX: or check? */
21933 DUK_UNREF(ctx);
21934
21935 /* Convert as one-based, but change month to zero-based to match the
21936 * Ecmascript Date built-in behavior 1:1.
21937 */
21938 flags = DUK_DATE_FLAG_ONEBASED | DUK_DATE_FLAG_NAN_TO_ZERO;
21939
21940 duk_bi_date_timeval_to_parts(timeval, parts, dparts, flags);
21941
21942 DUK_ASSERT(dparts[DUK_DATE_IDX_MONTH] >= 1.0 && dparts[DUK_DATE_IDX_MONTH] <= 12.0);
21943 comp->year = dparts[DUK_DATE_IDX_YEAR];
21944 comp->month = dparts[DUK_DATE_IDX_MONTH] - 1.0;
21945 comp->day = dparts[DUK_DATE_IDX_DAY];
21946 comp->hours = dparts[DUK_DATE_IDX_HOUR];
21947 comp->minutes = dparts[DUK_DATE_IDX_MINUTE];
21948 comp->seconds = dparts[DUK_DATE_IDX_SECOND];
21949 comp->milliseconds = dparts[DUK_DATE_IDX_MILLISECOND];
21950 comp->weekday = dparts[DUK_DATE_IDX_WEEKDAY];
21951}
21952
21953DUK_EXTERNAL duk_double_t duk_components_to_time(duk_context *ctx, duk_time_components *comp) {
21954 duk_double_t d;
21955 duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
21956 duk_uint_t flags;
21957
21958 DUK_ASSERT(ctx != NULL);
21959 DUK_ASSERT(comp != NULL); /* XXX: or check? */
21960 DUK_UNREF(ctx);
21961
21962 /* Match Date constructor behavior (with UTC time). Month is given
21963 * as zero-based. Day-of-month is given as one-based so normalize
21964 * it to zero-based as the internal conversion helpers expects all
21965 * components to be zero-based.
21966 */
21967 flags = 0;
21968
21969 /* XXX: expensive conversion; use array format in API instead, or unify
21970 * time provider and time API to use same struct?
21971 */
21972
21973 dparts[DUK_DATE_IDX_YEAR] = comp->year;
21974 dparts[DUK_DATE_IDX_MONTH] = comp->month;
21975 dparts[DUK_DATE_IDX_DAY] = comp->day - 1.0;
21976 dparts[DUK_DATE_IDX_HOUR] = comp->hours;
21977 dparts[DUK_DATE_IDX_MINUTE] = comp->minutes;
21978 dparts[DUK_DATE_IDX_SECOND] = comp->seconds;
21979 dparts[DUK_DATE_IDX_MILLISECOND] = comp->milliseconds;
21980 dparts[DUK_DATE_IDX_WEEKDAY] = 0; /* ignored */
21981
21982 d = duk_bi_date_get_timeval_from_dparts(dparts, flags);
21983
21984 return d;
21985}
21986/*
21987 * Array built-ins
21988 *
21989 * Most Array built-ins are intentionally generic in Ecmascript, and are
21990 * intended to work even when the 'this' binding is not an Array instance.
21991 * This Ecmascript feature is also used by much real world code. For this
21992 * reason the implementations here don't assume exotic Array behavior or
21993 * e.g. presence of a .length property. However, some algorithms have a
21994 * fast path for duk_harray backed actual Array instances, enabled when
21995 * footprint is not a concern.
21996 *
21997 * XXX: the "Throw" flag should be set for (almost?) all [[Put]] and
21998 * [[Delete]] operations, but it's currently false throughout. Go through
21999 * all put/delete cases and check throw flag use. Need a new API primitive
22000 * which allows throws flag to be specified.
22001 *
22002 * XXX: array lengths above 2G won't work reliably. There are many places
22003 * where one needs a full signed 32-bit range ([-0xffffffff, 0xffffffff],
22004 * i.e. -33- bits). Although array 'length' cannot be written to be outside
22005 * the unsigned 32-bit range (E5.1 Section 15.4.5.1 throws a RangeError if so)
22006 * some intermediate values may be above 0xffffffff and this may not be always
22007 * correctly handled now (duk_uint32_t is not enough for all algorithms).
22008 * For instance, push() can legitimately write entries beyond length 0xffffffff
22009 * and cause a RangeError only at the end. To do this properly, the current
22010 * push() implementation tracks the array index using a 'double' instead of a
22011 * duk_uint32_t (which is somewhat awkward). See test-bi-array-push-maxlen.js.
22012 *
22013 * On using "put" vs. "def" prop
22014 * =============================
22015 *
22016 * Code below must be careful to use the appropriate primitive as it matters
22017 * for compliance. When using "put" there may be inherited properties in
22018 * Array.prototype which cause side effects when values are written. When
22019 * using "define" there are no such side effects, and many test262 test cases
22020 * check for this (for real world code, such side effects are very rare).
22021 * Both "put" and "define" are used in the E5.1 specification; as a rule,
22022 * "put" is used when modifying an existing array (or a non-array 'this'
22023 * binding) and "define" for setting values into a fresh result array.
22024 */
22025
22026/* #include duk_internal.h -> already included */
22027
22028/* Perform an intermediate join when this many elements have been pushed
22029 * on the value stack.
22030 */
22031#define DUK__ARRAY_MID_JOIN_LIMIT 4096
22032
22033#if defined(DUK_USE_ARRAY_BUILTIN)
22034
22035/*
22036 * Shared helpers.
22037 */
22038
22039/* Shared entry code for many Array built-ins: the 'this' binding is pushed
22040 * on the value stack and object coerced, and the current .length is returned.
22041 * Note that length is left on stack (it could be popped, but that's not
22042 * usually necessary because call handling will clean it up automatically).
22043 */
22044DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32(duk_context *ctx) {
22045 duk_uint32_t len;
22046
22047 /* XXX: push more directly? */
22048 (void) duk_push_this_coercible_to_object(ctx);
22049 DUK_ASSERT_HOBJECT_VALID(duk_get_hobject(ctx, -1));
22050 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_LENGTH);
22051 len = duk_to_uint32(ctx, -1);
22052
22053 /* -> [ ... ToObject(this) ToUint32(length) ] */
22054 return len;
22055}
22056
22057DUK_LOCAL duk_uint32_t duk__push_this_obj_len_u32_limited(duk_context *ctx) {
22058 /* Range limited to [0, 0x7fffffff] range, i.e. range that can be
22059 * represented with duk_int32_t. Use this when the method doesn't
22060 * handle the full 32-bit unsigned range correctly.
22061 */
22062 duk_uint32_t ret = duk__push_this_obj_len_u32(ctx);
22063 if (DUK_UNLIKELY(ret >= 0x80000000UL)) {
22064 DUK_ERROR_RANGE_INVALID_LENGTH((duk_hthread *) ctx);
22065 }
22066 return ret;
22067}
22068
22069#if defined(DUK_USE_ARRAY_FASTPATH)
22070/* Check if 'this' binding is an Array instance (duk_harray) which satisfies
22071 * a few other guarantees for fast path operation. The fast path doesn't
22072 * need to handle all operations, even for duk_harrays, but must handle a
22073 * significant fraction to improve performance. Return a non-NULL duk_harray
22074 * pointer when all fast path criteria are met, NULL otherwise.
22075 */
22076DUK_LOCAL duk_harray *duk__arraypart_fastpath_this(duk_context *ctx) {
22077 duk_hthread *thr;
22078 duk_tval *tv;
22079 duk_hobject *h;
22080 duk_uint_t flags_mask, flags_bits, flags_value;
22081
22082 thr = (duk_hthread *) ctx;
22083 DUK_ASSERT(thr->valstack_bottom > thr->valstack); /* because call in progress */
22084 tv = DUK_GET_THIS_TVAL_PTR(thr);
22085
22086 /* Fast path requires that 'this' is a duk_harray. Read only arrays
22087 * (ROM backed) are also rejected for simplicity.
22088 */
22089 if (!DUK_TVAL_IS_OBJECT(tv)) {
22090 DUK_DD(DUK_DDPRINT("reject array fast path: not an object"));
22091 return NULL;
22092 }
22093 h = DUK_TVAL_GET_OBJECT(tv);
22094 DUK_ASSERT(h != NULL);
22095 flags_mask = DUK_HOBJECT_FLAG_ARRAY_PART | \
22096 DUK_HOBJECT_FLAG_EXOTIC_ARRAY | \
22097 DUK_HEAPHDR_FLAG_READONLY;
22098 flags_bits = DUK_HOBJECT_FLAG_ARRAY_PART | \
22099 DUK_HOBJECT_FLAG_EXOTIC_ARRAY;
22100 flags_value = DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) h);
22101 if ((flags_value & flags_mask) != flags_bits) {
22102 DUK_DD(DUK_DDPRINT("reject array fast path: object flag check failed"));
22103 return NULL;
22104 }
22105
22106 /* In some cases a duk_harray's 'length' may be larger than the
22107 * current array part allocation. Avoid the fast path in these
22108 * cases, so that all fast path code can safely assume that all
22109 * items in the range [0,length[ are backed by the current array
22110 * part allocation.
22111 */
22112 if (((duk_harray *) h)->length > DUK_HOBJECT_GET_ASIZE(h)) {
22113 DUK_DD(DUK_DDPRINT("reject array fast path: length > array part size"));
22114 return NULL;
22115 }
22116
22117 /* Guarantees for fast path. */
22118 DUK_ASSERT(h != NULL);
22119 DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(h) == 0 || DUK_HOBJECT_A_GET_BASE(thr->heap, h) != NULL);
22120 DUK_ASSERT(((duk_harray *) h)->length <= DUK_HOBJECT_GET_ASIZE(h));
22121
22122 DUK_DD(DUK_DDPRINT("array fast path allowed for: %!O", (duk_heaphdr *) h));
22123 return (duk_harray *) h;
22124}
22125#endif /* DUK_USE_ARRAY_FASTPATH */
22126
22127/*
22128 * Constructor
22129 */
22130
22131DUK_INTERNAL duk_ret_t duk_bi_array_constructor(duk_context *ctx) {
22132 duk_idx_t nargs;
22133 duk_harray *a;
22134 duk_double_t d;
22135 duk_uint32_t len;
22136 duk_uint32_t len_prealloc;
22137
22138 nargs = duk_get_top(ctx);
22139
22140 if (nargs == 1 && duk_is_number(ctx, 0)) {
22141 /* XXX: expensive check (also shared elsewhere - so add a shared internal API call?) */
22142 d = duk_get_number(ctx, 0);
22143 len = duk_to_uint32(ctx, 0);
22144 if (((duk_double_t) len) != d) {
22145 DUK_DCERROR_RANGE_INVALID_LENGTH((duk_hthread *) ctx);
22146 }
22147
22148 /* For small lengths create a dense preallocated array.
22149 * For large arrays preallocate an initial part.
22150 */
22151 len_prealloc = len < 64 ? len : 64;
22152 a = duk_push_harray_with_size(ctx, len_prealloc);
22153 DUK_ASSERT(a != NULL);
22154 a->length = len;
22155 return 1;
22156 }
22157
22158 duk_pack(ctx, nargs);
22159 return 1;
22160}
22161
22162/*
22163 * isArray()
22164 */
22165
22166DUK_INTERNAL duk_ret_t duk_bi_array_constructor_is_array(duk_context *ctx) {
22167 duk_hobject *h;
22168
22169 h = duk_get_hobject_with_class(ctx, 0, DUK_HOBJECT_CLASS_ARRAY);
22170 duk_push_boolean(ctx, (h != NULL));
22171 return 1;
22172}
22173
22174/*
22175 * toString()
22176 */
22177
22178DUK_INTERNAL duk_ret_t duk_bi_array_prototype_to_string(duk_context *ctx) {
22179 (void) duk_push_this_coercible_to_object(ctx);
22180 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_JOIN);
22181
22182 /* [ ... this func ] */
22183 if (!duk_is_callable(ctx, -1)) {
22184 /* Fall back to the initial (original) Object.toString(). We don't
22185 * currently have pointers to the built-in functions, only the top
22186 * level global objects (like "Array") so this is now done in a bit
22187 * of a hacky manner. It would be cleaner to push the (original)
22188 * function and use duk_call_method().
22189 */
22190
22191 /* XXX: 'this' will be ToObject() coerced twice, which is incorrect
22192 * but should have no visible side effects.
22193 */
22194 DUK_DDD(DUK_DDDPRINT("this.join is not callable, fall back to (original) Object.toString"));
22195 duk_set_top(ctx, 0);
22196 return duk_bi_object_prototype_to_string(ctx); /* has access to 'this' binding */
22197 }
22198
22199 /* [ ... this func ] */
22200
22201 duk_insert(ctx, -2);
22202
22203 /* [ ... func this ] */
22204
22205 DUK_DDD(DUK_DDDPRINT("calling: func=%!iT, this=%!iT",
22206 (duk_tval *) duk_get_tval(ctx, -2),
22207 (duk_tval *) duk_get_tval(ctx, -1)));
22208 duk_call_method(ctx, 0);
22209
22210 return 1;
22211}
22212
22213/*
22214 * concat()
22215 */
22216
22217DUK_INTERNAL duk_ret_t duk_bi_array_prototype_concat(duk_context *ctx) {
22218 duk_idx_t i, n;
22219 duk_uarridx_t idx, idx_last;
22220 duk_uarridx_t j, len;
22221 duk_hobject *h;
22222
22223 /* XXX: the insert here is a bit expensive if there are a lot of items.
22224 * It could also be special cased in the outermost for loop quite easily
22225 * (as the element is dup()'d anyway).
22226 */
22227
22228 (void) duk_push_this_coercible_to_object(ctx);
22229 duk_insert(ctx, 0);
22230 n = duk_get_top(ctx);
22231 duk_push_array(ctx); /* -> [ ToObject(this) item1 ... itemN arr ] */
22232
22233 /* NOTE: The Array special behaviors are NOT invoked by duk_xdef_prop_index()
22234 * (which differs from the official algorithm). If no error is thrown, this
22235 * doesn't matter as the length is updated at the end. However, if an error
22236 * is thrown, the length will be unset. That shouldn't matter because the
22237 * caller won't get a reference to the intermediate value.
22238 */
22239
22240 idx = 0;
22241 idx_last = 0;
22242 for (i = 0; i < n; i++) {
22243 DUK_ASSERT_TOP(ctx, n + 1);
22244
22245 /* [ ToObject(this) item1 ... itemN arr ] */
22246
22247 duk_dup(ctx, i);
22248 h = duk_get_hobject_with_class(ctx, -1, DUK_HOBJECT_CLASS_ARRAY);
22249 if (!h) {
22250 duk_xdef_prop_index_wec(ctx, -2, idx++);
22251 idx_last = idx;
22252 continue;
22253 }
22254
22255 /* [ ToObject(this) item1 ... itemN arr item(i) ] */
22256
22257 /* XXX: an array can have length higher than 32 bits; this is not handled
22258 * correctly now.
22259 */
22260 len = (duk_uarridx_t) duk_get_length(ctx, -1);
22261 for (j = 0; j < len; j++) {
22262 if (duk_get_prop_index(ctx, -1, j)) {
22263 /* [ ToObject(this) item1 ... itemN arr item(i) item(i)[j] ] */
22264 duk_xdef_prop_index_wec(ctx, -3, idx++);
22265 idx_last = idx;
22266 } else {
22267 idx++;
22268 duk_pop(ctx);
22269#if defined(DUK_USE_NONSTD_ARRAY_CONCAT_TRAILER)
22270 /* According to E5.1 Section 15.4.4.4 nonexistent trailing
22271 * elements do not affect 'length' of the result. Test262
22272 * and other engines disagree, so update idx_last here too.
22273 */
22274 idx_last = idx;
22275#else
22276 /* Strict standard behavior, ignore trailing elements for
22277 * result 'length'.
22278 */
22279#endif
22280 }
22281 }
22282 duk_pop(ctx);
22283 }
22284
22285 /* The E5.1 Section 15.4.4.4 algorithm doesn't set the length explicitly
22286 * in the end, but because we're operating with an internal value which
22287 * is known to be an array, this should be equivalent.
22288 */
22289 duk_push_uarridx(ctx, idx_last);
22290 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
22291
22292 DUK_ASSERT_TOP(ctx, n + 1);
22293 return 1;
22294}
22295
22296/*
22297 * join(), toLocaleString()
22298 *
22299 * Note: checking valstack is necessary, but only in the per-element loop.
22300 *
22301 * Note: the trivial approach of pushing all the elements on the value stack
22302 * and then calling duk_join() fails when the array contains a large number
22303 * of elements. This problem can't be offloaded to duk_join() because the
22304 * elements to join must be handled here and have special handling. Current
22305 * approach is to do intermediate joins with very large number of elements.
22306 * There is no fancy handling; the prefix gets re-joined multiple times.
22307 */
22308
22309DUK_INTERNAL duk_ret_t duk_bi_array_prototype_join_shared(duk_context *ctx) {
22310 duk_uint32_t len, count;
22311 duk_uint32_t idx;
22312 duk_small_int_t to_locale_string = duk_get_current_magic(ctx);
22313 duk_idx_t valstack_required;
22314
22315 /* For join(), nargs is 1. For toLocaleString(), nargs is 0 and
22316 * setting the top essentially pushes an undefined to the stack,
22317 * thus defaulting to a comma separator.
22318 */
22319 duk_set_top(ctx, 1);
22320 if (duk_is_undefined(ctx, 0)) {
22321 duk_pop(ctx);
22322 duk_push_hstring_stridx(ctx, DUK_STRIDX_COMMA);
22323 } else {
22324 duk_to_string(ctx, 0);
22325 }
22326
22327 len = duk__push_this_obj_len_u32(ctx);
22328
22329 /* [ sep ToObject(this) len ] */
22330
22331 DUK_DDD(DUK_DDDPRINT("sep=%!T, this=%!T, len=%lu",
22332 (duk_tval *) duk_get_tval(ctx, 0),
22333 (duk_tval *) duk_get_tval(ctx, 1),
22334 (unsigned long) len));
22335
22336 /* The extra (+4) is tight. */
22337 valstack_required = (len >= DUK__ARRAY_MID_JOIN_LIMIT ?
22338 DUK__ARRAY_MID_JOIN_LIMIT : len) + 4;
22339 duk_require_stack(ctx, valstack_required);
22340
22341 duk_dup_0(ctx);
22342
22343 /* [ sep ToObject(this) len sep ] */
22344
22345 count = 0;
22346 idx = 0;
22347 for (;;) {
22348 DUK_DDD(DUK_DDDPRINT("join idx=%ld", (long) idx));
22349 if (count >= DUK__ARRAY_MID_JOIN_LIMIT || /* intermediate join to avoid valstack overflow */
22350 idx >= len) { /* end of loop (careful with len==0) */
22351 /* [ sep ToObject(this) len sep str0 ... str(count-1) ] */
22352 DUK_DDD(DUK_DDDPRINT("mid/final join, count=%ld, idx=%ld, len=%ld",
22353 (long) count, (long) idx, (long) len));
22354 duk_join(ctx, (duk_idx_t) count); /* -> [ sep ToObject(this) len str ] */
22355 duk_dup_0(ctx); /* -> [ sep ToObject(this) len str sep ] */
22356 duk_insert(ctx, -2); /* -> [ sep ToObject(this) len sep str ] */
22357 count = 1;
22358 }
22359 if (idx >= len) {
22360 /* if true, the stack already contains the final result */
22361 break;
22362 }
22363
22364 duk_get_prop_index(ctx, 1, (duk_uarridx_t) idx);
22365 if (duk_is_null_or_undefined(ctx, -1)) {
22366 duk_pop(ctx);
22367 duk_push_hstring_empty(ctx);
22368 } else {
22369 if (to_locale_string) {
22370 duk_to_object(ctx, -1);
22371 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_TO_LOCALE_STRING);
22372 duk_insert(ctx, -2); /* -> [ ... toLocaleString ToObject(val) ] */
22373 duk_call_method(ctx, 0);
22374 }
22375 duk_to_string(ctx, -1);
22376 }
22377
22378 count++;
22379 idx++;
22380 }
22381
22382 /* [ sep ToObject(this) len sep result ] */
22383
22384 return 1;
22385}
22386
22387/*
22388 * pop(), push()
22389 */
22390
22391#if defined(DUK_USE_ARRAY_FASTPATH)
22392DUK_LOCAL duk_ret_t duk__array_pop_fastpath(duk_context *ctx, duk_harray *h_arr) {
22393 duk_hthread *thr;
22394 duk_tval *tv_arraypart;
22395 duk_tval *tv_val;
22396 duk_uint32_t len;
22397
22398 thr = (duk_hthread *) ctx;
22399
22400 tv_arraypart = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) h_arr);
22401 len = h_arr->length;
22402 if (len <= 0) {
22403 /* nop, return undefined */
22404 return 0;
22405 }
22406
22407 len--;
22408 h_arr->length = len;
22409
22410 /* Fast path doesn't check for an index property inherited from
22411 * Array.prototype. This is quite often acceptable; if not,
22412 * disable fast path.
22413 */
22414 DUK_ASSERT_VS_SPACE(thr);
22415 tv_val = tv_arraypart + len;
22416 if (DUK_TVAL_IS_UNUSED(tv_val)) {
22417 /* No net refcount change. Value stack already has
22418 * 'undefined' based on value stack init policy.
22419 */
22420 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top));
22421 DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv_val));
22422 } else {
22423 /* No net refcount change. */
22424 DUK_TVAL_SET_TVAL(thr->valstack_top, tv_val);
22425 DUK_TVAL_SET_UNUSED(tv_val);
22426 }
22427 thr->valstack_top++;
22428
22429 /* XXX: there's no shrink check in the fast path now */
22430
22431 return 1;
22432}
22433#endif /* DUK_USE_ARRAY_FASTPATH */
22434
22435DUK_INTERNAL duk_ret_t duk_bi_array_prototype_pop(duk_context *ctx) {
22436 duk_uint32_t len;
22437 duk_uint32_t idx;
22438#if defined(DUK_USE_ARRAY_FASTPATH)
22439 duk_harray *h_arr;
22440#endif
22441
22442 DUK_ASSERT_TOP(ctx, 0);
22443
22444#if defined(DUK_USE_ARRAY_FASTPATH)
22445 h_arr = duk__arraypart_fastpath_this(ctx);
22446 if (h_arr) {
22447 return duk__array_pop_fastpath(ctx, h_arr);
22448 }
22449#endif
22450
22451 /* XXX: Merge fastpath check into a related call (push this, coerce length, etc)? */
22452
22453 len = duk__push_this_obj_len_u32(ctx);
22454 if (len == 0) {
22455 duk_push_int(ctx, 0);
22456 duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_LENGTH);
22457 return 0;
22458 }
22459 idx = len - 1;
22460
22461 duk_get_prop_index(ctx, 0, (duk_uarridx_t) idx);
22462 duk_del_prop_index(ctx, 0, (duk_uarridx_t) idx);
22463 duk_push_u32(ctx, idx);
22464 duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_LENGTH);
22465 return 1;
22466}
22467
22468#if defined(DUK_USE_ARRAY_FASTPATH)
22469DUK_LOCAL duk_ret_t duk__array_push_fastpath(duk_context *ctx, duk_harray *h_arr) {
22470 duk_hthread *thr;
22471 duk_tval *tv_arraypart;
22472 duk_tval *tv_src;
22473 duk_tval *tv_dst;
22474 duk_uint32_t len;
22475 duk_idx_t i, n;
22476
22477 thr = (duk_hthread *) ctx;
22478
22479 len = h_arr->length;
22480 tv_arraypart = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) h_arr);
22481
22482 n = (duk_idx_t) (thr->valstack_top - thr->valstack_bottom);
22483 if (DUK_UNLIKELY(len + n < len)) {
22484 DUK_D(DUK_DPRINT("Array.prototype.push() would go beyond 32-bit length, throw"));
22485 DUK_DCERROR_RANGE_INVALID_LENGTH(thr); /* != 0 return value returned as is by caller */
22486 }
22487 if (len + n > DUK_HOBJECT_GET_ASIZE((duk_hobject *) h_arr)) {
22488 /* Array part would need to be extended. Rely on slow path
22489 * for now.
22490 *
22491 * XXX: Rework hobject code a bit and add extend support.
22492 */
22493 return 0;
22494 }
22495
22496 tv_src = thr->valstack_bottom;
22497 tv_dst = tv_arraypart + len;
22498 for (i = 0; i < n; i++) {
22499 /* No net refcount change; reset value stack values to
22500 * undefined to satisfy value stack init policy.
22501 */
22502 DUK_TVAL_SET_TVAL(tv_dst, tv_src);
22503 DUK_TVAL_SET_UNDEFINED(tv_src);
22504 tv_src++;
22505 tv_dst++;
22506 }
22507 thr->valstack_top = thr->valstack_bottom;
22508 len += n;
22509 h_arr->length = len;
22510
22511 DUK_ASSERT((duk_uint_t) len == len);
22512 duk_push_uint(ctx, (duk_uint_t) len);
22513 return 1;
22514}
22515#endif /* DUK_USE_ARRAY_FASTPATH */
22516
22517DUK_INTERNAL duk_ret_t duk_bi_array_prototype_push(duk_context *ctx) {
22518 /* Note: 'this' is not necessarily an Array object. The push()
22519 * algorithm is supposed to work for other kinds of objects too,
22520 * so the algorithm has e.g. an explicit update for the 'length'
22521 * property which is normally "magical" in arrays.
22522 */
22523
22524 duk_uint32_t len;
22525 duk_idx_t i, n;
22526#if defined(DUK_USE_ARRAY_FASTPATH)
22527 duk_harray *h_arr;
22528#endif
22529
22530#if defined(DUK_USE_ARRAY_FASTPATH)
22531 h_arr = duk__arraypart_fastpath_this(ctx);
22532 if (h_arr) {
22533 duk_ret_t rc;
22534 rc = duk__array_push_fastpath(ctx, h_arr);
22535 if (rc != 0) {
22536 return rc;
22537 }
22538 DUK_DD(DUK_DDPRINT("array push() fast path exited, resize case"));
22539 }
22540#endif
22541
22542 n = duk_get_top(ctx);
22543 len = duk__push_this_obj_len_u32(ctx);
22544
22545 /* [ arg1 ... argN obj length ] */
22546
22547 /* Technically Array.prototype.push() can create an Array with length
22548 * longer than 2^32-1, i.e. outside the 32-bit range. The final length
22549 * is *not* wrapped to 32 bits in the specification.
22550 *
22551 * This implementation tracks length with a uint32 because it's much
22552 * more practical.
22553 *
22554 * See: test-bi-array-push-maxlen.js.
22555 */
22556
22557 if (len + (duk_uint32_t) n < len) {
22558 DUK_D(DUK_DPRINT("Array.prototype.push() would go beyond 32-bit length, throw"));
22559 DUK_DCERROR_RANGE_INVALID_LENGTH((duk_hthread *) ctx);
22560 }
22561
22562 for (i = 0; i < n; i++) {
22563 duk_dup(ctx, i);
22564 duk_put_prop_index(ctx, -3, len + i);
22565 }
22566 len += n;
22567
22568 duk_push_u32(ctx, len);
22569 duk_dup_top(ctx);
22570 duk_put_prop_stridx_short(ctx, -4, DUK_STRIDX_LENGTH);
22571
22572 /* [ arg1 ... argN obj length new_length ] */
22573 return 1;
22574}
22575
22576/*
22577 * sort()
22578 *
22579 * Currently qsort with random pivot. This is now really, really slow,
22580 * because there is no fast path for array parts.
22581 *
22582 * Signed indices are used because qsort() leaves and degenerate cases
22583 * may use a negative offset.
22584 */
22585
22586DUK_LOCAL duk_small_int_t duk__array_sort_compare(duk_context *ctx, duk_int_t idx1, duk_int_t idx2) {
22587 duk_bool_t have1, have2;
22588 duk_bool_t undef1, undef2;
22589 duk_small_int_t ret;
22590 duk_idx_t idx_obj = 1; /* fixed offsets in valstack */
22591 duk_idx_t idx_fn = 0;
22592 duk_hstring *h1, *h2;
22593
22594 /* Fast exit if indices are identical. This is valid for a non-existent property,
22595 * for an undefined value, and almost always for ToString() coerced comparison of
22596 * arbitrary values (corner cases where this is not the case include e.g. a an
22597 * object with varying ToString() coercion).
22598 *
22599 * The specification does not prohibit "caching" of values read from the array, so
22600 * assuming equality for comparing an index with itself falls into the category of
22601 * "caching".
22602 *
22603 * Also, compareFn may be inconsistent, so skipping a call to compareFn here may
22604 * have an effect on the final result. The specification does not require any
22605 * specific behavior for inconsistent compare functions, so again, this fast path
22606 * is OK.
22607 */
22608
22609 if (idx1 == idx2) {
22610 DUK_DDD(DUK_DDDPRINT("duk__array_sort_compare: idx1=%ld, idx2=%ld -> indices identical, quick exit",
22611 (long) idx1, (long) idx2));
22612 return 0;
22613 }
22614
22615 have1 = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) idx1);
22616 have2 = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) idx2);
22617
22618 DUK_DDD(DUK_DDDPRINT("duk__array_sort_compare: idx1=%ld, idx2=%ld, have1=%ld, have2=%ld, val1=%!T, val2=%!T",
22619 (long) idx1, (long) idx2, (long) have1, (long) have2,
22620 (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1)));
22621
22622 if (have1) {
22623 if (have2) {
22624 ;
22625 } else {
22626 ret = -1;
22627 goto pop_ret;
22628 }
22629 } else {
22630 if (have2) {
22631 ret = 1;
22632 goto pop_ret;
22633 } else {
22634 ret = 0;
22635 goto pop_ret;
22636 }
22637 }
22638
22639 undef1 = duk_is_undefined(ctx, -2);
22640 undef2 = duk_is_undefined(ctx, -1);
22641 if (undef1) {
22642 if (undef2) {
22643 ret = 0;
22644 goto pop_ret;
22645 } else {
22646 ret = 1;
22647 goto pop_ret;
22648 }
22649 } else {
22650 if (undef2) {
22651 ret = -1;
22652 goto pop_ret;
22653 } else {
22654 ;
22655 }
22656 }
22657
22658 if (!duk_is_undefined(ctx, idx_fn)) {
22659 duk_double_t d;
22660
22661 /* No need to check callable; duk_call() will do that. */
22662 duk_dup(ctx, idx_fn); /* -> [ ... x y fn ] */
22663 duk_insert(ctx, -3); /* -> [ ... fn x y ] */
22664 duk_call(ctx, 2); /* -> [ ... res ] */
22665
22666 /* ES5 is a bit vague about what to do if the return value is
22667 * not a number. ES2015 provides a concrete description:
22668 * http://www.ecma-international.org/ecma-262/6.0/#sec-sortcompare.
22669 */
22670
22671 d = duk_to_number_m1(ctx);
22672 if (d < 0.0) {
22673 ret = -1;
22674 } else if (d > 0.0) {
22675 ret = 1;
22676 } else {
22677 /* Because NaN compares to false, NaN is handled here
22678 * without an explicit check above.
22679 */
22680 ret = 0;
22681 }
22682
22683 duk_pop(ctx);
22684 DUK_DDD(DUK_DDDPRINT("-> result %ld (from comparefn, after coercion)", (long) ret));
22685 return ret;
22686 }
22687
22688 /* string compare is the default (a bit oddly) */
22689
22690 /* XXX: any special handling for plain array; causes repeated coercion now? */
22691 h1 = duk_to_hstring(ctx, -2);
22692 h2 = duk_to_hstring_m1(ctx);
22693 DUK_ASSERT(h1 != NULL);
22694 DUK_ASSERT(h2 != NULL);
22695
22696 ret = duk_js_string_compare(h1, h2); /* retval is directly usable */
22697 goto pop_ret;
22698
22699 pop_ret:
22700 duk_pop_2(ctx);
22701 DUK_DDD(DUK_DDDPRINT("-> result %ld", (long) ret));
22702 return ret;
22703}
22704
22705DUK_LOCAL void duk__array_sort_swap(duk_context *ctx, duk_int_t l, duk_int_t r) {
22706 duk_bool_t have_l, have_r;
22707 duk_idx_t idx_obj = 1; /* fixed offset in valstack */
22708
22709 if (l == r) {
22710 return;
22711 }
22712
22713 /* swap elements; deal with non-existent elements correctly */
22714 have_l = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) l);
22715 have_r = duk_get_prop_index(ctx, idx_obj, (duk_uarridx_t) r);
22716
22717 if (have_r) {
22718 /* right exists, [[Put]] regardless whether or not left exists */
22719 duk_put_prop_index(ctx, idx_obj, (duk_uarridx_t) l);
22720 } else {
22721 duk_del_prop_index(ctx, idx_obj, (duk_uarridx_t) l);
22722 duk_pop(ctx);
22723 }
22724
22725 if (have_l) {
22726 duk_put_prop_index(ctx, idx_obj, (duk_uarridx_t) r);
22727 } else {
22728 duk_del_prop_index(ctx, idx_obj, (duk_uarridx_t) r);
22729 duk_pop(ctx);
22730 }
22731}
22732
22733#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
22734/* Debug print which visualizes the qsort partitioning process. */
22735DUK_LOCAL void duk__debuglog_qsort_state(duk_context *ctx, duk_int_t lo, duk_int_t hi, duk_int_t pivot) {
22736 char buf[4096];
22737 char *ptr = buf;
22738 duk_int_t i, n;
22739 n = (duk_int_t) duk_get_length(ctx, 1);
22740 if (n > 4000) {
22741 n = 4000;
22742 }
22743 *ptr++ = '[';
22744 for (i = 0; i < n; i++) {
22745 if (i == pivot) {
22746 *ptr++ = '|';
22747 } else if (i == lo) {
22748 *ptr++ = '<';
22749 } else if (i == hi) {
22750 *ptr++ = '>';
22751 } else if (i >= lo && i <= hi) {
22752 *ptr++ = '-';
22753 } else {
22754 *ptr++ = ' ';
22755 }
22756 }
22757 *ptr++ = ']';
22758 *ptr++ = '\0';
22759
22760 DUK_DDD(DUK_DDDPRINT("%s (lo=%ld, hi=%ld, pivot=%ld)",
22761 (const char *) buf, (long) lo, (long) hi, (long) pivot));
22762}
22763#endif
22764
22765DUK_LOCAL void duk__array_qsort(duk_context *ctx, duk_int_t lo, duk_int_t hi) {
22766 duk_int_t p, l, r;
22767
22768 /* The lo/hi indices may be crossed and hi < 0 is possible at entry. */
22769
22770 DUK_DDD(DUK_DDDPRINT("duk__array_qsort: lo=%ld, hi=%ld, obj=%!T",
22771 (long) lo, (long) hi, (duk_tval *) duk_get_tval(ctx, 1)));
22772
22773 DUK_ASSERT_TOP(ctx, 3);
22774
22775 /* In some cases it may be that lo > hi, or hi < 0; these
22776 * degenerate cases happen e.g. for empty arrays, and in
22777 * recursion leaves.
22778 */
22779
22780 /* trivial cases */
22781 if (hi - lo < 1) {
22782 DUK_DDD(DUK_DDDPRINT("degenerate case, return immediately"));
22783 return;
22784 }
22785 DUK_ASSERT(hi > lo);
22786 DUK_ASSERT(hi - lo + 1 >= 2);
22787
22788 /* randomized pivot selection */
22789 p = lo + (duk_int_t) (DUK_UTIL_GET_RANDOM_DOUBLE((duk_hthread *) ctx) * (duk_double_t) (hi - lo + 1));
22790 DUK_ASSERT(p >= lo && p <= hi);
22791 DUK_DDD(DUK_DDDPRINT("lo=%ld, hi=%ld, chose pivot p=%ld", (long) lo, (long) hi, (long) p));
22792
22793 /* move pivot out of the way */
22794 duk__array_sort_swap(ctx, p, lo);
22795 p = lo;
22796 DUK_DDD(DUK_DDDPRINT("pivot moved out of the way: %!T", (duk_tval *) duk_get_tval(ctx, 1)));
22797
22798 l = lo + 1;
22799 r = hi;
22800 for (;;) {
22801 /* find elements to swap */
22802 for (;;) {
22803 DUK_DDD(DUK_DDDPRINT("left scan: l=%ld, r=%ld, p=%ld",
22804 (long) l, (long) r, (long) p));
22805 if (l >= hi) {
22806 break;
22807 }
22808 if (duk__array_sort_compare(ctx, l, p) >= 0) { /* !(l < p) */
22809 break;
22810 }
22811 l++;
22812 }
22813 for (;;) {
22814 DUK_DDD(DUK_DDDPRINT("right scan: l=%ld, r=%ld, p=%ld",
22815 (long) l, (long) r, (long) p));
22816 if (r <= lo) {
22817 break;
22818 }
22819 if (duk__array_sort_compare(ctx, p, r) >= 0) { /* !(p < r) */
22820 break;
22821 }
22822 r--;
22823 }
22824 if (l >= r) {
22825 goto done;
22826 }
22827 DUK_ASSERT(l < r);
22828
22829 DUK_DDD(DUK_DDDPRINT("swap %ld and %ld", (long) l, (long) r));
22830
22831 duk__array_sort_swap(ctx, l, r);
22832
22833 DUK_DDD(DUK_DDDPRINT("after swap: %!T", (duk_tval *) duk_get_tval(ctx, 1)));
22834 l++;
22835 r--;
22836 }
22837 done:
22838 /* Note that 'l' and 'r' may cross, i.e. r < l */
22839 DUK_ASSERT(l >= lo && l <= hi);
22840 DUK_ASSERT(r >= lo && r <= hi);
22841
22842 /* XXX: there's no explicit recursion bound here now. For the average
22843 * qsort recursion depth O(log n) that's not really necessary: e.g. for
22844 * 2**32 recursion depth would be about 32 which is OK. However, qsort
22845 * worst case recursion depth is O(n) which may be a problem.
22846 */
22847
22848 /* move pivot to its final place */
22849 DUK_DDD(DUK_DDDPRINT("before final pivot swap: %!T", (duk_tval *) duk_get_tval(ctx, 1)));
22850 duk__array_sort_swap(ctx, lo, r);
22851
22852#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
22853 duk__debuglog_qsort_state(ctx, lo, hi, r);
22854#endif
22855
22856 DUK_DDD(DUK_DDDPRINT("recurse: pivot=%ld, obj=%!T", (long) r, (duk_tval *) duk_get_tval(ctx, 1)));
22857 duk__array_qsort(ctx, lo, r - 1);
22858 duk__array_qsort(ctx, r + 1, hi);
22859}
22860
22861DUK_INTERNAL duk_ret_t duk_bi_array_prototype_sort(duk_context *ctx) {
22862 duk_uint32_t len;
22863
22864 /* XXX: len >= 0x80000000 won't work below because a signed type
22865 * is needed by qsort.
22866 */
22867 len = duk__push_this_obj_len_u32_limited(ctx);
22868
22869 /* stack[0] = compareFn
22870 * stack[1] = ToObject(this)
22871 * stack[2] = ToUint32(length)
22872 */
22873
22874 if (len > 0) {
22875 /* avoid degenerate cases, so that (len - 1) won't underflow */
22876 duk__array_qsort(ctx, (duk_int_t) 0, (duk_int_t) (len - 1));
22877 }
22878
22879 DUK_ASSERT_TOP(ctx, 3);
22880 duk_pop(ctx);
22881 return 1; /* return ToObject(this) */
22882}
22883
22884/*
22885 * splice()
22886 */
22887
22888/* XXX: this compiles to over 500 bytes now, even without special handling
22889 * for an array part. Uses signed ints so does not handle full array range correctly.
22890 */
22891
22892/* XXX: can shift() / unshift() use the same helper?
22893 * shift() is (close to?) <--> splice(0, 1)
22894 * unshift is (close to?) <--> splice(0, 0, [items])?
22895 */
22896
22897DUK_INTERNAL duk_ret_t duk_bi_array_prototype_splice(duk_context *ctx) {
22898 duk_idx_t nargs;
22899 duk_uint32_t len;
22900 duk_bool_t have_delcount;
22901 duk_int_t item_count;
22902 duk_int_t act_start;
22903 duk_int_t del_count;
22904 duk_int_t i, n;
22905
22906 DUK_UNREF(have_delcount);
22907
22908 nargs = duk_get_top(ctx);
22909 if (nargs < 2) {
22910 duk_set_top(ctx, 2);
22911 nargs = 2;
22912 have_delcount = 0;
22913 } else {
22914 have_delcount = 1;
22915 }
22916
22917 /* XXX: len >= 0x80000000 won't work below because we need to be
22918 * able to represent -len.
22919 */
22920 len = duk__push_this_obj_len_u32_limited(ctx);
22921
22922 act_start = duk_to_int_clamped(ctx, 0, -((duk_int_t) len), (duk_int_t) len);
22923 if (act_start < 0) {
22924 act_start = len + act_start;
22925 }
22926 DUK_ASSERT(act_start >= 0 && act_start <= (duk_int_t) len);
22927
22928#if defined(DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT)
22929 if (have_delcount) {
22930#endif
22931 del_count = duk_to_int_clamped(ctx, 1, 0, len - act_start);
22932#if defined(DUK_USE_NONSTD_ARRAY_SPLICE_DELCOUNT)
22933 } else {
22934 /* E5.1 standard behavior when deleteCount is not given would be
22935 * to treat it just like if 'undefined' was given, which coerces
22936 * ultimately to 0. Real world behavior is to splice to the end
22937 * of array, see test-bi-array-proto-splice-no-delcount.js.
22938 */
22939 del_count = len - act_start;
22940 }
22941#endif
22942
22943 DUK_ASSERT(nargs >= 2);
22944 item_count = (duk_int_t) (nargs - 2);
22945
22946 DUK_ASSERT(del_count >= 0 && del_count <= (duk_int_t) len - act_start);
22947 DUK_ASSERT(del_count + act_start <= (duk_int_t) len);
22948
22949 /* For now, restrict result array into 32-bit length range. */
22950 if (((duk_double_t) len) - ((duk_double_t) del_count) + ((duk_double_t) item_count) > (duk_double_t) DUK_UINT32_MAX) {
22951 DUK_D(DUK_DPRINT("Array.prototype.splice() would go beyond 32-bit length, throw"));
22952 DUK_DCERROR_RANGE_INVALID_LENGTH((duk_hthread *) ctx);
22953 }
22954
22955 duk_push_array(ctx);
22956
22957 /* stack[0] = start
22958 * stack[1] = deleteCount
22959 * stack[2...nargs-1] = items
22960 * stack[nargs] = ToObject(this) -3
22961 * stack[nargs+1] = ToUint32(length) -2
22962 * stack[nargs+2] = result array -1
22963 */
22964
22965 DUK_ASSERT_TOP(ctx, nargs + 3);
22966
22967 /* Step 9: copy elements-to-be-deleted into the result array */
22968
22969 for (i = 0; i < del_count; i++) {
22970 if (duk_get_prop_index(ctx, -3, (duk_uarridx_t) (act_start + i))) {
22971 duk_xdef_prop_index_wec(ctx, -2, i); /* throw flag irrelevant (false in std alg) */
22972 } else {
22973 duk_pop(ctx);
22974 }
22975 }
22976 duk_push_u32(ctx, (duk_uint32_t) del_count);
22977 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
22978
22979 /* Steps 12 and 13: reorganize elements to make room for itemCount elements */
22980
22981 if (item_count < del_count) {
22982 /* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 1
22983 * -> [ A B F G H ] (conceptual intermediate step)
22984 * -> [ A B . F G H ] (placeholder marked)
22985 * [ A B C F G H ] (actual result at this point, C will be replaced)
22986 */
22987
22988 DUK_ASSERT_TOP(ctx, nargs + 3);
22989
22990 n = len - del_count;
22991 for (i = act_start; i < n; i++) {
22992 if (duk_get_prop_index(ctx, -3, (duk_uarridx_t) (i + del_count))) {
22993 duk_put_prop_index(ctx, -4, (duk_uarridx_t) (i + item_count));
22994 } else {
22995 duk_pop(ctx);
22996 duk_del_prop_index(ctx, -3, (duk_uarridx_t) (i + item_count));
22997 }
22998 }
22999
23000 DUK_ASSERT_TOP(ctx, nargs + 3);
23001
23002 /* loop iterator init and limit changed from standard algorithm */
23003 n = len - del_count + item_count;
23004 for (i = len - 1; i >= n; i--) {
23005 duk_del_prop_index(ctx, -3, (duk_uarridx_t) i);
23006 }
23007
23008 DUK_ASSERT_TOP(ctx, nargs + 3);
23009 } else if (item_count > del_count) {
23010 /* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 4
23011 * -> [ A B F G H ] (conceptual intermediate step)
23012 * -> [ A B . . . . F G H ] (placeholder marked)
23013 * [ A B C D E F F G H ] (actual result at this point)
23014 */
23015
23016 DUK_ASSERT_TOP(ctx, nargs + 3);
23017
23018 /* loop iterator init and limit changed from standard algorithm */
23019 for (i = len - del_count - 1; i >= act_start; i--) {
23020 if (duk_get_prop_index(ctx, -3, (duk_uarridx_t) (i + del_count))) {
23021 duk_put_prop_index(ctx, -4, (duk_uarridx_t) (i + item_count));
23022 } else {
23023 duk_pop(ctx);
23024 duk_del_prop_index(ctx, -3, (duk_uarridx_t) (i + item_count));
23025 }
23026 }
23027
23028 DUK_ASSERT_TOP(ctx, nargs + 3);
23029 } else {
23030 /* [ A B C D E F G H ] rel_index = 2, del_count 3, item count 3
23031 * -> [ A B F G H ] (conceptual intermediate step)
23032 * -> [ A B . . . F G H ] (placeholder marked)
23033 * [ A B C D E F G H ] (actual result at this point)
23034 */
23035 }
23036 DUK_ASSERT_TOP(ctx, nargs + 3);
23037
23038 /* Step 15: insert itemCount elements into the hole made above */
23039
23040 for (i = 0; i < item_count; i++) {
23041 duk_dup(ctx, i + 2); /* args start at index 2 */
23042 duk_put_prop_index(ctx, -4, (duk_uarridx_t) (act_start + i));
23043 }
23044
23045 /* Step 16: update length; note that the final length may be above 32 bit range
23046 * (but we checked above that this isn't the case here)
23047 */
23048
23049 duk_push_u32(ctx, len - del_count + item_count);
23050 duk_put_prop_stridx_short(ctx, -4, DUK_STRIDX_LENGTH);
23051
23052 /* result array is already at the top of stack */
23053 DUK_ASSERT_TOP(ctx, nargs + 3);
23054 return 1;
23055}
23056
23057/*
23058 * reverse()
23059 */
23060
23061DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reverse(duk_context *ctx) {
23062 duk_uint32_t len;
23063 duk_uint32_t middle;
23064 duk_uint32_t lower, upper;
23065 duk_bool_t have_lower, have_upper;
23066
23067 len = duk__push_this_obj_len_u32(ctx);
23068 middle = len / 2;
23069
23070 /* If len <= 1, middle will be 0 and for-loop bails out
23071 * immediately (0 < 0 -> false).
23072 */
23073
23074 for (lower = 0; lower < middle; lower++) {
23075 DUK_ASSERT(len >= 2);
23076 DUK_ASSERT_TOP(ctx, 2);
23077
23078 DUK_ASSERT(len >= lower + 1);
23079 upper = len - lower - 1;
23080
23081 have_lower = duk_get_prop_index(ctx, -2, (duk_uarridx_t) lower);
23082 have_upper = duk_get_prop_index(ctx, -3, (duk_uarridx_t) upper);
23083
23084 /* [ ToObject(this) ToUint32(length) lowerValue upperValue ] */
23085
23086 if (have_upper) {
23087 duk_put_prop_index(ctx, -4, (duk_uarridx_t) lower);
23088 } else {
23089 duk_del_prop_index(ctx, -4, (duk_uarridx_t) lower);
23090 duk_pop(ctx);
23091 }
23092
23093 if (have_lower) {
23094 duk_put_prop_index(ctx, -3, (duk_uarridx_t) upper);
23095 } else {
23096 duk_del_prop_index(ctx, -3, (duk_uarridx_t) upper);
23097 duk_pop(ctx);
23098 }
23099
23100 DUK_ASSERT_TOP(ctx, 2);
23101 }
23102
23103 DUK_ASSERT_TOP(ctx, 2);
23104 duk_pop(ctx); /* -> [ ToObject(this) ] */
23105 return 1;
23106}
23107
23108/*
23109 * slice()
23110 */
23111
23112DUK_INTERNAL duk_ret_t duk_bi_array_prototype_slice(duk_context *ctx) {
23113 duk_uint32_t len;
23114 duk_int_t start, end;
23115 duk_int_t i;
23116 duk_uarridx_t idx;
23117 duk_uint32_t res_length = 0;
23118
23119 /* XXX: len >= 0x80000000 won't work below because we need to be
23120 * able to represent -len.
23121 */
23122 len = duk__push_this_obj_len_u32_limited(ctx);
23123 duk_push_array(ctx);
23124
23125 /* stack[0] = start
23126 * stack[1] = end
23127 * stack[2] = ToObject(this)
23128 * stack[3] = ToUint32(length)
23129 * stack[4] = result array
23130 */
23131
23132 start = duk_to_int_clamped(ctx, 0, -((duk_int_t) len), (duk_int_t) len);
23133 if (start < 0) {
23134 start = len + start;
23135 }
23136 /* XXX: could duk_is_undefined() provide defaulting undefined to 'len'
23137 * (the upper limit)?
23138 */
23139 if (duk_is_undefined(ctx, 1)) {
23140 end = len;
23141 } else {
23142 end = duk_to_int_clamped(ctx, 1, -((duk_int_t) len), (duk_int_t) len);
23143 if (end < 0) {
23144 end = len + end;
23145 }
23146 }
23147 DUK_ASSERT(start >= 0 && (duk_uint32_t) start <= len);
23148 DUK_ASSERT(end >= 0 && (duk_uint32_t) end <= len);
23149
23150 idx = 0;
23151 for (i = start; i < end; i++) {
23152 DUK_ASSERT_TOP(ctx, 5);
23153 if (duk_get_prop_index(ctx, 2, (duk_uarridx_t) i)) {
23154 duk_xdef_prop_index_wec(ctx, 4, idx);
23155 res_length = idx + 1;
23156 } else {
23157 duk_pop(ctx);
23158 }
23159 idx++;
23160 DUK_ASSERT_TOP(ctx, 5);
23161 }
23162
23163 duk_push_u32(ctx, res_length);
23164 duk_xdef_prop_stridx_short(ctx, 4, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
23165
23166 DUK_ASSERT_TOP(ctx, 5);
23167 return 1;
23168}
23169
23170/*
23171 * shift()
23172 */
23173
23174DUK_INTERNAL duk_ret_t duk_bi_array_prototype_shift(duk_context *ctx) {
23175 duk_uint32_t len;
23176 duk_uint32_t i;
23177
23178 len = duk__push_this_obj_len_u32(ctx);
23179 if (len == 0) {
23180 duk_push_int(ctx, 0);
23181 duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_LENGTH);
23182 return 0;
23183 }
23184
23185 duk_get_prop_index(ctx, 0, 0);
23186
23187 /* stack[0] = object (this)
23188 * stack[1] = ToUint32(length)
23189 * stack[2] = elem at index 0 (retval)
23190 */
23191
23192 for (i = 1; i < len; i++) {
23193 DUK_ASSERT_TOP(ctx, 3);
23194 if (duk_get_prop_index(ctx, 0, (duk_uarridx_t) i)) {
23195 /* fromPresent = true */
23196 duk_put_prop_index(ctx, 0, (duk_uarridx_t) (i - 1));
23197 } else {
23198 /* fromPresent = false */
23199 duk_del_prop_index(ctx, 0, (duk_uarridx_t) (i - 1));
23200 duk_pop(ctx);
23201 }
23202 }
23203 duk_del_prop_index(ctx, 0, (duk_uarridx_t) (len - 1));
23204
23205 duk_push_u32(ctx, (duk_uint32_t) (len - 1));
23206 duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_LENGTH);
23207
23208 DUK_ASSERT_TOP(ctx, 3);
23209 return 1;
23210}
23211
23212/*
23213 * unshift()
23214 */
23215
23216DUK_INTERNAL duk_ret_t duk_bi_array_prototype_unshift(duk_context *ctx) {
23217 duk_idx_t nargs;
23218 duk_uint32_t len;
23219 duk_uint32_t i;
23220
23221 nargs = duk_get_top(ctx);
23222 len = duk__push_this_obj_len_u32(ctx);
23223
23224 /* stack[0...nargs-1] = unshift args (vararg)
23225 * stack[nargs] = ToObject(this)
23226 * stack[nargs+1] = ToUint32(length)
23227 */
23228
23229 DUK_ASSERT_TOP(ctx, nargs + 2);
23230
23231 /* Note: unshift() may operate on indices above unsigned 32-bit range
23232 * and the final length may be >= 2**32. However, we restrict the
23233 * final result to 32-bit range for practicality.
23234 */
23235
23236 if (len + (duk_uint32_t) nargs < len) {
23237 DUK_D(DUK_DPRINT("Array.prototype.unshift() would go beyond 32-bit length, throw"));
23238 DUK_DCERROR_RANGE_INVALID_LENGTH((duk_hthread *) ctx);
23239 }
23240
23241 i = len;
23242 while (i > 0) {
23243 DUK_ASSERT_TOP(ctx, nargs + 2);
23244 i--;
23245 /* k+argCount-1; note that may be above 32-bit range */
23246
23247 if (duk_get_prop_index(ctx, -2, (duk_uarridx_t) i)) {
23248 /* fromPresent = true */
23249 /* [ ... ToObject(this) ToUint32(length) val ] */
23250 duk_put_prop_index(ctx, -3, (duk_uarridx_t) (i + nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */
23251 } else {
23252 /* fromPresent = false */
23253 /* [ ... ToObject(this) ToUint32(length) val ] */
23254 duk_pop(ctx);
23255 duk_del_prop_index(ctx, -2, (duk_uarridx_t) (i + nargs)); /* -> [ ... ToObject(this) ToUint32(length) ] */
23256 }
23257 DUK_ASSERT_TOP(ctx, nargs + 2);
23258 }
23259
23260 for (i = 0; i < (duk_uint32_t) nargs; i++) {
23261 DUK_ASSERT_TOP(ctx, nargs + 2);
23262 duk_dup(ctx, i); /* -> [ ... ToObject(this) ToUint32(length) arg[i] ] */
23263 duk_put_prop_index(ctx, -3, (duk_uarridx_t) i);
23264 DUK_ASSERT_TOP(ctx, nargs + 2);
23265 }
23266
23267 DUK_ASSERT_TOP(ctx, nargs + 2);
23268 duk_push_u32(ctx, len + nargs);
23269 duk_dup_top(ctx); /* -> [ ... ToObject(this) ToUint32(length) final_len final_len ] */
23270 duk_put_prop_stridx_short(ctx, -4, DUK_STRIDX_LENGTH);
23271 return 1;
23272}
23273
23274/*
23275 * indexOf(), lastIndexOf()
23276 */
23277
23278DUK_INTERNAL duk_ret_t duk_bi_array_prototype_indexof_shared(duk_context *ctx) {
23279 duk_idx_t nargs;
23280 duk_int_t i, len;
23281 duk_int_t from_idx;
23282 duk_small_int_t idx_step = duk_get_current_magic(ctx); /* idx_step is +1 for indexOf, -1 for lastIndexOf */
23283
23284 /* lastIndexOf() needs to be a vararg function because we must distinguish
23285 * between an undefined fromIndex and a "not given" fromIndex; indexOf() is
23286 * made vararg for symmetry although it doesn't strictly need to be.
23287 */
23288
23289 nargs = duk_get_top(ctx);
23290 duk_set_top(ctx, 2);
23291
23292 /* XXX: must be able to represent -len */
23293 len = (duk_int_t) duk__push_this_obj_len_u32_limited(ctx);
23294 if (len == 0) {
23295 goto not_found;
23296 }
23297
23298 /* Index clamping is a bit tricky, we must ensure that we'll only iterate
23299 * through elements that exist and that the specific requirements from E5.1
23300 * Sections 15.4.4.14 and 15.4.4.15 are fulfilled; especially:
23301 *
23302 * - indexOf: clamp to [-len,len], negative handling -> [0,len],
23303 * if clamped result is len, for-loop bails out immediately
23304 *
23305 * - lastIndexOf: clamp to [-len-1, len-1], negative handling -> [-1, len-1],
23306 * if clamped result is -1, for-loop bails out immediately
23307 *
23308 * If fromIndex is not given, ToInteger(undefined) = 0, which is correct
23309 * for indexOf() but incorrect for lastIndexOf(). Hence special handling,
23310 * and why lastIndexOf() needs to be a vararg function.
23311 */
23312
23313 if (nargs >= 2) {
23314 /* indexOf: clamp fromIndex to [-len, len]
23315 * (if fromIndex == len, for-loop terminates directly)
23316 *
23317 * lastIndexOf: clamp fromIndex to [-len - 1, len - 1]
23318 * (if clamped to -len-1 -> fromIndex becomes -1, terminates for-loop directly)
23319 */
23320 from_idx = duk_to_int_clamped(ctx,
23321 1,
23322 (idx_step > 0 ? -len : -len - 1),
23323 (idx_step > 0 ? len : len - 1));
23324 if (from_idx < 0) {
23325 /* for lastIndexOf, result may be -1 (mark immediate termination) */
23326 from_idx = len + from_idx;
23327 }
23328 } else {
23329 /* for indexOf, ToInteger(undefined) would be 0, i.e. correct, but
23330 * handle both indexOf and lastIndexOf specially here.
23331 */
23332 if (idx_step > 0) {
23333 from_idx = 0;
23334 } else {
23335 from_idx = len - 1;
23336 }
23337 }
23338
23339 /* stack[0] = searchElement
23340 * stack[1] = fromIndex
23341 * stack[2] = object
23342 * stack[3] = length (not needed, but not popped above)
23343 */
23344
23345 for (i = from_idx; i >= 0 && i < len; i += idx_step) {
23346 DUK_ASSERT_TOP(ctx, 4);
23347
23348 if (duk_get_prop_index(ctx, 2, (duk_uarridx_t) i)) {
23349 DUK_ASSERT_TOP(ctx, 5);
23350 if (duk_strict_equals(ctx, 0, 4)) {
23351 duk_push_int(ctx, i);
23352 return 1;
23353 }
23354 }
23355
23356 duk_pop(ctx);
23357 }
23358
23359 not_found:
23360 duk_push_int(ctx, -1);
23361 return 1;
23362}
23363
23364/*
23365 * every(), some(), forEach(), map(), filter()
23366 */
23367
23368#define DUK__ITER_EVERY 0
23369#define DUK__ITER_SOME 1
23370#define DUK__ITER_FOREACH 2
23371#define DUK__ITER_MAP 3
23372#define DUK__ITER_FILTER 4
23373
23374/* XXX: This helper is a bit awkward because the handling for the different iteration
23375 * callers is quite different. This now compiles to a bit less than 500 bytes, so with
23376 * 5 callers the net result is about 100 bytes / caller.
23377 */
23378
23379DUK_INTERNAL duk_ret_t duk_bi_array_prototype_iter_shared(duk_context *ctx) {
23380 duk_uint32_t len;
23381 duk_uint32_t i;
23382 duk_uarridx_t k;
23383 duk_bool_t bval;
23384 duk_small_int_t iter_type = duk_get_current_magic(ctx);
23385 duk_uint32_t res_length = 0;
23386
23387 /* each call this helper serves has nargs==2 */
23388 DUK_ASSERT_TOP(ctx, 2);
23389
23390 len = duk__push_this_obj_len_u32(ctx);
23391 duk_require_callable(ctx, 0);
23392 /* if thisArg not supplied, behave as if undefined was supplied */
23393
23394 if (iter_type == DUK__ITER_MAP || iter_type == DUK__ITER_FILTER) {
23395 duk_push_array(ctx);
23396 } else {
23397 duk_push_undefined(ctx);
23398 }
23399
23400 /* stack[0] = callback
23401 * stack[1] = thisArg
23402 * stack[2] = object
23403 * stack[3] = ToUint32(length) (unused, but avoid unnecessary pop)
23404 * stack[4] = result array (or undefined)
23405 */
23406
23407 k = 0; /* result index for filter() */
23408 for (i = 0; i < len; i++) {
23409 DUK_ASSERT_TOP(ctx, 5);
23410
23411 if (!duk_get_prop_index(ctx, 2, (duk_uarridx_t) i)) {
23412#if defined(DUK_USE_NONSTD_ARRAY_MAP_TRAILER)
23413 /* Real world behavior for map(): trailing non-existent
23414 * elements don't invoke the user callback, but are still
23415 * counted towards result 'length'.
23416 */
23417 if (iter_type == DUK__ITER_MAP) {
23418 res_length = i + 1;
23419 }
23420#else
23421 /* Standard behavior for map(): trailing non-existent
23422 * elements don't invoke the user callback and are not
23423 * counted towards result 'length'.
23424 */
23425#endif
23426 duk_pop(ctx);
23427 continue;
23428 }
23429
23430 /* The original value needs to be preserved for filter(), hence
23431 * this funny order. We can't re-get the value because of side
23432 * effects.
23433 */
23434
23435 duk_dup_0(ctx);
23436 duk_dup_1(ctx);
23437 duk_dup_m3(ctx);
23438 duk_push_u32(ctx, i);
23439 duk_dup_2(ctx); /* [ ... val callback thisArg val i obj ] */
23440 duk_call_method(ctx, 3); /* -> [ ... val retval ] */
23441
23442 switch (iter_type) {
23443 case DUK__ITER_EVERY:
23444 bval = duk_to_boolean(ctx, -1);
23445 if (!bval) {
23446 /* stack top contains 'false' */
23447 return 1;
23448 }
23449 break;
23450 case DUK__ITER_SOME:
23451 bval = duk_to_boolean(ctx, -1);
23452 if (bval) {
23453 /* stack top contains 'true' */
23454 return 1;
23455 }
23456 break;
23457 case DUK__ITER_FOREACH:
23458 /* nop */
23459 break;
23460 case DUK__ITER_MAP:
23461 duk_dup_top(ctx);
23462 duk_xdef_prop_index_wec(ctx, 4, (duk_uarridx_t) i); /* retval to result[i] */
23463 res_length = i + 1;
23464 break;
23465 case DUK__ITER_FILTER:
23466 bval = duk_to_boolean(ctx, -1);
23467 if (bval) {
23468 duk_dup_m2(ctx); /* orig value */
23469 duk_xdef_prop_index_wec(ctx, 4, (duk_uarridx_t) k);
23470 k++;
23471 res_length = k;
23472 }
23473 break;
23474 default:
23475 DUK_UNREACHABLE();
23476 break;
23477 }
23478 duk_pop_2(ctx);
23479
23480 DUK_ASSERT_TOP(ctx, 5);
23481 }
23482
23483 switch (iter_type) {
23484 case DUK__ITER_EVERY:
23485 duk_push_true(ctx);
23486 break;
23487 case DUK__ITER_SOME:
23488 duk_push_false(ctx);
23489 break;
23490 case DUK__ITER_FOREACH:
23491 duk_push_undefined(ctx);
23492 break;
23493 case DUK__ITER_MAP:
23494 case DUK__ITER_FILTER:
23495 DUK_ASSERT_TOP(ctx, 5);
23496 DUK_ASSERT(duk_is_array(ctx, -1)); /* topmost element is the result array already */
23497 duk_push_u32(ctx, res_length);
23498 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_W);
23499 break;
23500 default:
23501 DUK_UNREACHABLE();
23502 break;
23503 }
23504
23505 return 1;
23506}
23507
23508/*
23509 * reduce(), reduceRight()
23510 */
23511
23512DUK_INTERNAL duk_ret_t duk_bi_array_prototype_reduce_shared(duk_context *ctx) {
23513 duk_idx_t nargs;
23514 duk_bool_t have_acc;
23515 duk_uint32_t i, len;
23516 duk_small_int_t idx_step = duk_get_current_magic(ctx); /* idx_step is +1 for reduce, -1 for reduceRight */
23517
23518 /* We're a varargs function because we need to detect whether
23519 * initialValue was given or not.
23520 */
23521 nargs = duk_get_top(ctx);
23522 DUK_DDD(DUK_DDDPRINT("nargs=%ld", (long) nargs));
23523
23524 duk_set_top(ctx, 2);
23525 len = duk__push_this_obj_len_u32(ctx);
23526 duk_require_callable(ctx, 0);
23527
23528 /* stack[0] = callback fn
23529 * stack[1] = initialValue
23530 * stack[2] = object (coerced this)
23531 * stack[3] = length (not needed, but not popped above)
23532 * stack[4] = accumulator
23533 */
23534
23535 have_acc = 0;
23536 if (nargs >= 2) {
23537 duk_dup_1(ctx);
23538 have_acc = 1;
23539 }
23540 DUK_DDD(DUK_DDDPRINT("have_acc=%ld, acc=%!T",
23541 (long) have_acc, (duk_tval *) duk_get_tval(ctx, 3)));
23542
23543 /* For len == 0, i is initialized to len - 1 which underflows.
23544 * The condition (i < len) will then exit the for-loop on the
23545 * first round which is correct. Similarly, loop termination
23546 * happens by i underflowing.
23547 */
23548
23549 for (i = (idx_step >= 0 ? 0 : len - 1);
23550 i < len; /* i >= 0 would always be true */
23551 i += idx_step) {
23552 DUK_DDD(DUK_DDDPRINT("i=%ld, len=%ld, have_acc=%ld, top=%ld, acc=%!T",
23553 (long) i, (long) len, (long) have_acc,
23554 (long) duk_get_top(ctx),
23555 (duk_tval *) duk_get_tval(ctx, 4)));
23556
23557 DUK_ASSERT((have_acc && duk_get_top(ctx) == 5) ||
23558 (!have_acc && duk_get_top(ctx) == 4));
23559
23560 if (!duk_has_prop_index(ctx, 2, (duk_uarridx_t) i)) {
23561 continue;
23562 }
23563
23564 if (!have_acc) {
23565 DUK_ASSERT_TOP(ctx, 4);
23566 duk_get_prop_index(ctx, 2, (duk_uarridx_t) i);
23567 have_acc = 1;
23568 DUK_ASSERT_TOP(ctx, 5);
23569 } else {
23570 DUK_ASSERT_TOP(ctx, 5);
23571 duk_dup_0(ctx);
23572 duk_dup(ctx, 4);
23573 duk_get_prop_index(ctx, 2, (duk_uarridx_t) i);
23574 duk_push_u32(ctx, i);
23575 duk_dup_2(ctx);
23576 DUK_DDD(DUK_DDDPRINT("calling reduce function: func=%!T, prev=%!T, curr=%!T, idx=%!T, obj=%!T",
23577 (duk_tval *) duk_get_tval(ctx, -5), (duk_tval *) duk_get_tval(ctx, -4),
23578 (duk_tval *) duk_get_tval(ctx, -3), (duk_tval *) duk_get_tval(ctx, -2),
23579 (duk_tval *) duk_get_tval(ctx, -1)));
23580 duk_call(ctx, 4);
23581 DUK_DDD(DUK_DDDPRINT("-> result: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
23582 duk_replace(ctx, 4);
23583 DUK_ASSERT_TOP(ctx, 5);
23584 }
23585 }
23586
23587 if (!have_acc) {
23588 DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
23589 }
23590
23591 DUK_ASSERT_TOP(ctx, 5);
23592 return 1;
23593}
23594
23595#endif /* DUK_USE_ARRAY_BUILTIN */
23596
23597/* automatic undefs */
23598#undef DUK__ARRAY_MID_JOIN_LIMIT
23599#undef DUK__ITER_EVERY
23600#undef DUK__ITER_FILTER
23601#undef DUK__ITER_FOREACH
23602#undef DUK__ITER_MAP
23603#undef DUK__ITER_SOME
23604/*
23605 * Boolean built-ins
23606 */
23607
23608/* #include duk_internal.h -> already included */
23609
23610#if defined(DUK_USE_BOOLEAN_BUILTIN)
23611
23612/* Shared helper to provide toString() and valueOf(). Checks 'this', gets
23613 * the primitive value to stack top, and optionally coerces with ToString().
23614 */
23615DUK_INTERNAL duk_ret_t duk_bi_boolean_prototype_tostring_shared(duk_context *ctx) {
23616 duk_tval *tv;
23617 duk_hobject *h;
23618 duk_small_int_t coerce_tostring = duk_get_current_magic(ctx);
23619
23620 /* XXX: there is room to use a shared helper here, many built-ins
23621 * check the 'this' type, and if it's an object, check its class,
23622 * then get its internal value, etc.
23623 */
23624
23625 duk_push_this(ctx);
23626 tv = duk_get_tval(ctx, -1);
23627 DUK_ASSERT(tv != NULL);
23628
23629 if (DUK_TVAL_IS_BOOLEAN(tv)) {
23630 goto type_ok;
23631 } else if (DUK_TVAL_IS_OBJECT(tv)) {
23632 h = DUK_TVAL_GET_OBJECT(tv);
23633 DUK_ASSERT(h != NULL);
23634
23635 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_BOOLEAN) {
23636 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_VALUE);
23637 DUK_ASSERT(duk_is_boolean(ctx, -1));
23638 goto type_ok;
23639 }
23640 }
23641
23642 DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
23643 /* never here */
23644
23645 type_ok:
23646 if (coerce_tostring) {
23647 duk_to_string(ctx, -1);
23648 }
23649 return 1;
23650}
23651
23652DUK_INTERNAL duk_ret_t duk_bi_boolean_constructor(duk_context *ctx) {
23653 duk_hthread *thr = (duk_hthread *) ctx;
23654 duk_hobject *h_this;
23655
23656 DUK_UNREF(thr);
23657
23658 duk_to_boolean(ctx, 0);
23659
23660 if (duk_is_constructor_call(ctx)) {
23661 /* XXX: helper; rely on Boolean.prototype as being non-writable, non-configurable */
23662 duk_push_this(ctx);
23663 h_this = duk_known_hobject(ctx, -1);
23664 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_this) == thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE]);
23665
23666 DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_BOOLEAN);
23667
23668 duk_dup_0(ctx); /* -> [ val obj val ] */
23669 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE); /* XXX: proper flags? */
23670 } /* unbalanced stack */
23671
23672 return 1;
23673}
23674
23675#endif /* DUK_USE_BOOLEAN_BUILTIN */
23676/*
23677 * ES2015 TypedArray and Node.js Buffer built-ins
23678 */
23679
23680/* #include duk_internal.h -> already included */
23681
23682/*
23683 * Helpers for buffer handling, enabled with DUK_USE_BUFFEROBJECT_SUPPORT.
23684 */
23685
23686#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
23687/* Map class number (minus DUK_HOBJECT_CLASS_BUFOBJ_MIN) to a bidx for the
23688 * default internal prototype.
23689 */
23690static const duk_uint8_t duk__buffer_proto_from_classnum[] = {
23691 DUK_BIDX_ARRAYBUFFER_PROTOTYPE,
23692 DUK_BIDX_DATAVIEW_PROTOTYPE,
23693 DUK_BIDX_INT8ARRAY_PROTOTYPE,
23694 DUK_BIDX_UINT8ARRAY_PROTOTYPE,
23695 DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE,
23696 DUK_BIDX_INT16ARRAY_PROTOTYPE,
23697 DUK_BIDX_UINT16ARRAY_PROTOTYPE,
23698 DUK_BIDX_INT32ARRAY_PROTOTYPE,
23699 DUK_BIDX_UINT32ARRAY_PROTOTYPE,
23700 DUK_BIDX_FLOAT32ARRAY_PROTOTYPE,
23701 DUK_BIDX_FLOAT64ARRAY_PROTOTYPE
23702};
23703
23704/* Map DUK_HBUFOBJ_ELEM_xxx to duk_hobject class number.
23705 * Sync with duk_hbufobj.h and duk_hobject.h.
23706 */
23707static const duk_uint8_t duk__buffer_class_from_elemtype[9] = {
23708 DUK_HOBJECT_CLASS_UINT8ARRAY,
23709 DUK_HOBJECT_CLASS_UINT8CLAMPEDARRAY,
23710 DUK_HOBJECT_CLASS_INT8ARRAY,
23711 DUK_HOBJECT_CLASS_UINT16ARRAY,
23712 DUK_HOBJECT_CLASS_INT16ARRAY,
23713 DUK_HOBJECT_CLASS_UINT32ARRAY,
23714 DUK_HOBJECT_CLASS_INT32ARRAY,
23715 DUK_HOBJECT_CLASS_FLOAT32ARRAY,
23716 DUK_HOBJECT_CLASS_FLOAT64ARRAY
23717};
23718
23719/* Map DUK_HBUFOBJ_ELEM_xxx to prototype object built-in index.
23720 * Sync with duk_hbufobj.h.
23721 */
23722static const duk_uint8_t duk__buffer_proto_from_elemtype[9] = {
23723 DUK_BIDX_UINT8ARRAY_PROTOTYPE,
23724 DUK_BIDX_UINT8CLAMPEDARRAY_PROTOTYPE,
23725 DUK_BIDX_INT8ARRAY_PROTOTYPE,
23726 DUK_BIDX_UINT16ARRAY_PROTOTYPE,
23727 DUK_BIDX_INT16ARRAY_PROTOTYPE,
23728 DUK_BIDX_UINT32ARRAY_PROTOTYPE,
23729 DUK_BIDX_INT32ARRAY_PROTOTYPE,
23730 DUK_BIDX_FLOAT32ARRAY_PROTOTYPE,
23731 DUK_BIDX_FLOAT64ARRAY_PROTOTYPE
23732};
23733
23734/* Map DUK__FLD_xxx to byte size. */
23735static const duk_uint8_t duk__buffer_nbytes_from_fldtype[6] = {
23736 1, /* DUK__FLD_8BIT */
23737 2, /* DUK__FLD_16BIT */
23738 4, /* DUK__FLD_32BIT */
23739 4, /* DUK__FLD_FLOAT */
23740 8, /* DUK__FLD_DOUBLE */
23741 0 /* DUK__FLD_VARINT; not relevant here */
23742};
23743
23744/* Bitfield for each DUK_HBUFOBJ_ELEM_xxx indicating which element types
23745 * are compatible with a blind byte copy for the TypedArray set() method (also
23746 * used for TypedArray constructor). Array index is target buffer elem type,
23747 * bitfield indicates compatible source types. The types must have same byte
23748 * size and they must be coercion compatible.
23749 */
23750#if !defined(DUK_USE_PREFER_SIZE)
23751static duk_uint16_t duk__buffer_elemtype_copy_compatible[9] = {
23752 /* xxx -> DUK_HBUFOBJ_ELEM_UINT8 */
23753 (1U << DUK_HBUFOBJ_ELEM_UINT8) |
23754 (1U << DUK_HBUFOBJ_ELEM_UINT8CLAMPED) |
23755 (1U << DUK_HBUFOBJ_ELEM_INT8),
23756
23757 /* xxx -> DUK_HBUFOBJ_ELEM_UINT8CLAMPED
23758 * Note: INT8 is -not- copy compatible, e.g. -1 would coerce to 0x00.
23759 */
23760 (1U << DUK_HBUFOBJ_ELEM_UINT8) |
23761 (1U << DUK_HBUFOBJ_ELEM_UINT8CLAMPED),
23762
23763 /* xxx -> DUK_HBUFOBJ_ELEM_INT8 */
23764 (1U << DUK_HBUFOBJ_ELEM_UINT8) |
23765 (1U << DUK_HBUFOBJ_ELEM_UINT8CLAMPED) |
23766 (1U << DUK_HBUFOBJ_ELEM_INT8),
23767
23768 /* xxx -> DUK_HBUFOBJ_ELEM_UINT16 */
23769 (1U << DUK_HBUFOBJ_ELEM_UINT16) |
23770 (1U << DUK_HBUFOBJ_ELEM_INT16),
23771
23772 /* xxx -> DUK_HBUFOBJ_ELEM_INT16 */
23773 (1U << DUK_HBUFOBJ_ELEM_UINT16) |
23774 (1U << DUK_HBUFOBJ_ELEM_INT16),
23775
23776 /* xxx -> DUK_HBUFOBJ_ELEM_UINT32 */
23777 (1U << DUK_HBUFOBJ_ELEM_UINT32) |
23778 (1U << DUK_HBUFOBJ_ELEM_INT32),
23779
23780 /* xxx -> DUK_HBUFOBJ_ELEM_INT32 */
23781 (1U << DUK_HBUFOBJ_ELEM_UINT32) |
23782 (1U << DUK_HBUFOBJ_ELEM_INT32),
23783
23784 /* xxx -> DUK_HBUFOBJ_ELEM_FLOAT32 */
23785 (1U << DUK_HBUFOBJ_ELEM_FLOAT32),
23786
23787 /* xxx -> DUK_HBUFOBJ_ELEM_FLOAT64 */
23788 (1U << DUK_HBUFOBJ_ELEM_FLOAT64)
23789};
23790#endif /* !DUK_USE_PREFER_SIZE */
23791
23792DUK_LOCAL duk_hbufobj *duk__hbufobj_promote_this(duk_context *ctx) {
23793 duk_hthread *thr;
23794 duk_tval *tv_dst;
23795 duk_hbufobj *res;
23796
23797 thr = (duk_hthread *) ctx;
23798 duk_push_this(ctx);
23799 DUK_ASSERT(duk_is_buffer(ctx, -1));
23800 res = (duk_hbufobj *) duk_to_hobject(ctx, -1);
23801 DUK_ASSERT_HBUFOBJ_VALID(res);
23802 DUK_DD(DUK_DDPRINT("promoted 'this' automatically to an ArrayBuffer: %!iT", duk_get_tval(ctx, -1)));
23803
23804 tv_dst = duk_get_borrowed_this_tval(ctx);
23805 DUK_TVAL_SET_OBJECT_UPDREF(thr, tv_dst, (duk_hobject *) res);
23806 duk_pop(ctx);
23807
23808 return res;
23809}
23810
23811#define DUK__BUFOBJ_FLAG_THROW (1 << 0)
23812#define DUK__BUFOBJ_FLAG_PROMOTE (1 << 1)
23813
23814/* Shared helper. When DUK__BUFOBJ_FLAG_PROMOTE is given, the return value is
23815 * always a duk_hbufobj *. Without the flag the return value can also be a
23816 * plain buffer, and the caller must check for it using DUK_HEAPHDR_IS_BUFFER().
23817 */
23818DUK_LOCAL duk_heaphdr *duk__getrequire_bufobj_this(duk_context *ctx, duk_small_uint_t flags) {
23819 duk_hthread *thr;
23820 duk_tval *tv;
23821 duk_hbufobj *h_this;
23822
23823 DUK_ASSERT(ctx != NULL);
23824 thr = (duk_hthread *) ctx;
23825
23826 tv = duk_get_borrowed_this_tval(ctx);
23827 DUK_ASSERT(tv != NULL);
23828
23829 if (DUK_TVAL_IS_OBJECT(tv)) {
23830 h_this = (duk_hbufobj *) DUK_TVAL_GET_OBJECT(tv);
23831 DUK_ASSERT(h_this != NULL);
23832 if (DUK_HOBJECT_IS_BUFOBJ((duk_hobject *) h_this)) {
23833 DUK_ASSERT_HBUFOBJ_VALID(h_this);
23834 return (duk_heaphdr *) h_this;
23835 }
23836 } else if (DUK_TVAL_IS_BUFFER(tv)) {
23837 if (flags & DUK__BUFOBJ_FLAG_PROMOTE) {
23838 /* Promote a plain buffer to a Uint8Array. This is very
23839 * inefficient but allows plain buffer to be used wherever an
23840 * Uint8Array is used with very small cost; hot path functions
23841 * like index read/write calls should provide direct buffer
23842 * support to avoid promotion.
23843 */
23844 /* XXX: make this conditional to a flag if call sites need it? */
23845 h_this = duk__hbufobj_promote_this(ctx);
23846 DUK_ASSERT(h_this != NULL);
23847 DUK_ASSERT_HBUFOBJ_VALID(h_this);
23848 return (duk_heaphdr *) h_this;
23849 } else {
23850 /* XXX: ugly, share return pointer for duk_hbuffer. */
23851 return (duk_heaphdr *) DUK_TVAL_GET_BUFFER(tv);
23852 }
23853 }
23854
23855 if (flags & DUK__BUFOBJ_FLAG_THROW) {
23856 DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER);
23857 }
23858 return NULL;
23859}
23860
23861/* Check that 'this' is a duk_hbufobj and return a pointer to it. */
23862DUK_LOCAL duk_hbufobj *duk__get_bufobj_this(duk_context *ctx) {
23863 return (duk_hbufobj *) duk__getrequire_bufobj_this(ctx, DUK__BUFOBJ_FLAG_PROMOTE);
23864}
23865
23866/* Check that 'this' is a duk_hbufobj and return a pointer to it
23867 * (NULL if not).
23868 */
23869DUK_LOCAL duk_hbufobj *duk__require_bufobj_this(duk_context *ctx) {
23870 return (duk_hbufobj *) duk__getrequire_bufobj_this(ctx, DUK__BUFOBJ_FLAG_THROW | DUK__BUFOBJ_FLAG_PROMOTE);
23871}
23872
23873/* Check that value is a duk_hbufobj and return a pointer to it. */
23874DUK_LOCAL duk_hbufobj *duk__require_bufobj_value(duk_context *ctx, duk_idx_t idx) {
23875 duk_hthread *thr;
23876 duk_tval *tv;
23877 duk_hbufobj *h_obj;
23878
23879 thr = (duk_hthread *) ctx;
23880
23881 /* Don't accept relative indices now. */
23882 DUK_ASSERT(idx >= 0);
23883
23884 tv = duk_require_tval(ctx, idx);
23885 DUK_ASSERT(tv != NULL);
23886 if (DUK_TVAL_IS_OBJECT(tv)) {
23887 h_obj = (duk_hbufobj *) DUK_TVAL_GET_OBJECT(tv);
23888 DUK_ASSERT(h_obj != NULL);
23889 if (DUK_HOBJECT_IS_BUFOBJ((duk_hobject *) h_obj)) {
23890 DUK_ASSERT_HBUFOBJ_VALID(h_obj);
23891 return h_obj;
23892 }
23893 } else if (DUK_TVAL_IS_BUFFER(tv)) {
23894 h_obj = (duk_hbufobj *) duk_to_hobject(ctx, idx);
23895 DUK_ASSERT(h_obj != NULL);
23896 DUK_ASSERT_HBUFOBJ_VALID(h_obj);
23897 return h_obj;
23898 }
23899
23900 DUK_ERROR_TYPE(thr, DUK_STR_NOT_BUFFER);
23901 return NULL; /* not reachable */
23902}
23903
23904DUK_LOCAL void duk__set_bufobj_buffer(duk_context *ctx, duk_hbufobj *h_bufobj, duk_hbuffer *h_val) {
23905 duk_hthread *thr;
23906
23907 thr = (duk_hthread *) ctx;
23908 DUK_UNREF(thr);
23909
23910 DUK_ASSERT(ctx != NULL);
23911 DUK_ASSERT(h_bufobj != NULL);
23912 DUK_ASSERT(h_bufobj->buf == NULL); /* no need to decref */
23913 DUK_ASSERT(h_val != NULL);
23914 DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
23915
23916 h_bufobj->buf = h_val;
23917 DUK_HBUFFER_INCREF(thr, h_val);
23918 h_bufobj->length = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_val);
23919 DUK_ASSERT(h_bufobj->shift == 0);
23920 DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFOBJ_ELEM_UINT8);
23921 DUK_ASSERT(h_bufobj->is_typedarray == 0);
23922
23923 DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
23924}
23925
23926DUK_LOCAL duk_hbufobj *duk__push_arraybuffer_with_length(duk_context *ctx, duk_uint_t len) {
23927 duk_hbuffer *h_val;
23928 duk_hbufobj *h_bufobj;
23929
23930 (void) duk_push_fixed_buffer_zero(ctx, (duk_size_t) len);
23931 h_val = (duk_hbuffer *) duk_known_hbuffer(ctx, -1);
23932
23933 h_bufobj = duk_push_bufobj_raw(ctx,
23934 DUK_HOBJECT_FLAG_EXTENSIBLE |
23935 DUK_HOBJECT_FLAG_BUFOBJ |
23936 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
23937 DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
23938 DUK_ASSERT(h_bufobj != NULL);
23939
23940 duk__set_bufobj_buffer(ctx, h_bufobj, h_val);
23941 DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
23942
23943 return h_bufobj;
23944}
23945
23946/* Shared offset/length coercion helper. */
23947DUK_LOCAL void duk__resolve_offset_opt_length(duk_context *ctx,
23948 duk_hbufobj *h_bufarg,
23949 duk_idx_t idx_offset,
23950 duk_idx_t idx_length,
23951 duk_uint_t *out_offset,
23952 duk_uint_t *out_length,
23953 duk_bool_t throw_flag) {
23954 duk_hthread *thr;
23955 duk_int_t offset_signed;
23956 duk_int_t length_signed;
23957 duk_uint_t offset;
23958 duk_uint_t length;
23959
23960 thr = (duk_hthread *) ctx;
23961 DUK_UNREF(thr);
23962
23963 offset_signed = duk_to_int(ctx, idx_offset);
23964 if (offset_signed < 0) {
23965 goto fail_range;
23966 }
23967 offset = (duk_uint_t) offset_signed;
23968 if (offset > h_bufarg->length) {
23969 goto fail_range;
23970 }
23971 DUK_ASSERT_DISABLE(offset >= 0); /* unsigned */
23972 DUK_ASSERT(offset <= h_bufarg->length);
23973
23974 if (duk_is_undefined(ctx, idx_length)) {
23975 DUK_ASSERT(h_bufarg->length >= offset);
23976 length = h_bufarg->length - offset; /* >= 0 */
23977 } else {
23978 length_signed = duk_to_int(ctx, idx_length);
23979 if (length_signed < 0) {
23980 goto fail_range;
23981 }
23982 length = (duk_uint_t) length_signed;
23983 DUK_ASSERT(h_bufarg->length >= offset);
23984 if (length > h_bufarg->length - offset) {
23985 /* Unlike for negative arguments, some call sites
23986 * want length to be clamped if it's positive.
23987 */
23988 if (throw_flag) {
23989 goto fail_range;
23990 } else {
23991 length = h_bufarg->length - offset;
23992 }
23993 }
23994 }
23995 DUK_ASSERT_DISABLE(length >= 0); /* unsigned */
23996 DUK_ASSERT(offset + length <= h_bufarg->length);
23997
23998 *out_offset = offset;
23999 *out_length = length;
24000 return;
24001
24002 fail_range:
24003 DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARGS);
24004}
24005
24006/* Shared lenient buffer length clamping helper. No negative indices, no
24007 * element/byte shifting.
24008 */
24009DUK_LOCAL void duk__clamp_startend_nonegidx_noshift(duk_context *ctx,
24010 duk_int_t buffer_length,
24011 duk_idx_t idx_start,
24012 duk_idx_t idx_end,
24013 duk_int_t *out_start_offset,
24014 duk_int_t *out_end_offset) {
24015 duk_int_t start_offset;
24016 duk_int_t end_offset;
24017
24018 DUK_ASSERT(out_start_offset != NULL);
24019 DUK_ASSERT(out_end_offset != NULL);
24020
24021 /* undefined coerces to zero which is correct */
24022 start_offset = duk_to_int_clamped(ctx, idx_start, 0, buffer_length);
24023 if (duk_is_undefined(ctx, idx_end)) {
24024 end_offset = buffer_length;
24025 } else {
24026 end_offset = duk_to_int_clamped(ctx, idx_end, start_offset, buffer_length);
24027 }
24028
24029 DUK_ASSERT(start_offset >= 0);
24030 DUK_ASSERT(start_offset <= buffer_length);
24031 DUK_ASSERT(end_offset >= 0);
24032 DUK_ASSERT(end_offset <= buffer_length);
24033 DUK_ASSERT(start_offset <= end_offset);
24034
24035 *out_start_offset = start_offset;
24036 *out_end_offset = end_offset;
24037}
24038
24039/* Shared lenient buffer length clamping helper. Indices are treated as
24040 * element indices (though output values are byte offsets) which only
24041 * really matters for TypedArray views as other buffer object have a zero
24042 * shift. Negative indices are counted from end of input slice; crossed
24043 * indices are clamped to zero length; and final indices are clamped
24044 * against input slice. Used for e.g. ArrayBuffer slice().
24045 */
24046DUK_LOCAL void duk__clamp_startend_negidx_shifted(duk_context *ctx,
24047 duk_int_t buffer_length,
24048 duk_uint8_t buffer_shift,
24049 duk_idx_t idx_start,
24050 duk_idx_t idx_end,
24051 duk_int_t *out_start_offset,
24052 duk_int_t *out_end_offset) {
24053 duk_int_t start_offset;
24054 duk_int_t end_offset;
24055
24056 DUK_ASSERT(out_start_offset != NULL);
24057 DUK_ASSERT(out_end_offset != NULL);
24058
24059 buffer_length >>= buffer_shift; /* as (full) elements */
24060
24061 /* Resolve start/end offset as element indices first; arguments
24062 * at idx_start/idx_end are element offsets. Working with element
24063 * indices first also avoids potential for wrapping.
24064 */
24065
24066 start_offset = duk_to_int(ctx, idx_start);
24067 if (start_offset < 0) {
24068 start_offset = buffer_length + start_offset;
24069 }
24070 if (duk_is_undefined(ctx, idx_end)) {
24071 end_offset = buffer_length;
24072 } else {
24073 end_offset = duk_to_int(ctx, idx_end);
24074 if (end_offset < 0) {
24075 end_offset = buffer_length + end_offset;
24076 }
24077 }
24078 /* Note: start_offset/end_offset can still be < 0 here. */
24079
24080 if (start_offset < 0) {
24081 start_offset = 0;
24082 } else if (start_offset > buffer_length) {
24083 start_offset = buffer_length;
24084 }
24085 if (end_offset < start_offset) {
24086 end_offset = start_offset;
24087 } else if (end_offset > buffer_length) {
24088 end_offset = buffer_length;
24089 }
24090 DUK_ASSERT(start_offset >= 0);
24091 DUK_ASSERT(start_offset <= buffer_length);
24092 DUK_ASSERT(end_offset >= 0);
24093 DUK_ASSERT(end_offset <= buffer_length);
24094 DUK_ASSERT(start_offset <= end_offset);
24095
24096 /* Convert indices to byte offsets. */
24097 start_offset <<= buffer_shift;
24098 end_offset <<= buffer_shift;
24099
24100 *out_start_offset = start_offset;
24101 *out_end_offset = end_offset;
24102}
24103
24104DUK_INTERNAL void duk_hbufobj_promote_plain(duk_context *ctx, duk_idx_t idx) {
24105 if (duk_is_buffer(ctx, idx)) {
24106 duk_to_object(ctx, idx);
24107 }
24108}
24109
24110DUK_INTERNAL void duk_hbufobj_push_uint8array_from_plain(duk_hthread *thr, duk_hbuffer *h_buf) {
24111 duk_context *ctx;
24112
24113 ctx = (duk_context *) thr;
24114
24115 /* Push Uint8Array which will share the same underlying buffer as
24116 * the plain buffer argument. Also create an ArrayBuffer with the
24117 * same backing for the result .buffer property.
24118 */
24119
24120 duk_push_hbuffer(ctx, h_buf);
24121 duk_push_buffer_object(ctx, -1, 0, (duk_size_t) DUK_HBUFFER_GET_SIZE(h_buf), DUK_BUFOBJ_UINT8ARRAY);
24122 duk_remove_m2(ctx);
24123
24124#if 0
24125 /* More verbose equivalent; maybe useful if e.g. .buffer is omitted. */
24126 h_bufobj = duk_push_bufobj_raw(ctx,
24127 DUK_HOBJECT_FLAG_EXTENSIBLE |
24128 DUK_HOBJECT_FLAG_BUFOBJ |
24129 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_UINT8ARRAY),
24130 DUK_BIDX_UINT8ARRAY_PROTOTYPE);
24131 DUK_ASSERT(h_bufobj != NULL);
24132 duk__set_bufobj_buffer(ctx, h_bufobj, h_buf);
24133 h_bufobj->is_typedarray = 1;
24134 DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
24135
24136 h_arrbuf = duk_push_bufobj_raw(ctx,
24137 DUK_HOBJECT_FLAG_EXTENSIBLE |
24138 DUK_HOBJECT_FLAG_BUFOBJ |
24139 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
24140 DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
24141 DUK_ASSERT(h_arrbuf != NULL);
24142 duk__set_bufobj_buffer(ctx, h_arrbuf, h_buf);
24143 DUK_ASSERT(h_arrbuf->is_typedarray == 0);
24144 DUK_ASSERT_HBUFOBJ_VALID(h_arrbuf);
24145
24146 DUK_ASSERT(h_bufobj->buf_prop == NULL);
24147 h_bufobj->buf_prop = (duk_hobject *) h_arrbuf;
24148 DUK_ASSERT(h_arrbuf != NULL);
24149 DUK_HBUFOBJ_INCREF(thr, h_arrbuf);
24150 duk_pop(ctx);
24151#endif
24152}
24153
24154/* Indexed read helper for buffer objects, also called from outside this file. */
24155DUK_INTERNAL void duk_hbufobj_push_validated_read(duk_context *ctx, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) {
24157
24158 DUK_MEMCPY((void *) du.uc, (const void *) p, (size_t) elem_size);
24159
24160 switch (h_bufobj->elem_type) {
24161 case DUK_HBUFOBJ_ELEM_UINT8:
24162 case DUK_HBUFOBJ_ELEM_UINT8CLAMPED:
24163 duk_push_uint(ctx, (duk_uint_t) du.uc[0]);
24164 break;
24165 case DUK_HBUFOBJ_ELEM_INT8:
24166 duk_push_int(ctx, (duk_int_t) (duk_int8_t) du.uc[0]);
24167 break;
24168 case DUK_HBUFOBJ_ELEM_UINT16:
24169 duk_push_uint(ctx, (duk_uint_t) du.us[0]);
24170 break;
24171 case DUK_HBUFOBJ_ELEM_INT16:
24172 duk_push_int(ctx, (duk_int_t) (duk_int16_t) du.us[0]);
24173 break;
24174 case DUK_HBUFOBJ_ELEM_UINT32:
24175 duk_push_uint(ctx, (duk_uint_t) du.ui[0]);
24176 break;
24177 case DUK_HBUFOBJ_ELEM_INT32:
24178 duk_push_int(ctx, (duk_int_t) (duk_int32_t) du.ui[0]);
24179 break;
24180 case DUK_HBUFOBJ_ELEM_FLOAT32:
24181 duk_push_number(ctx, (duk_double_t) du.f[0]);
24182 break;
24183 case DUK_HBUFOBJ_ELEM_FLOAT64:
24184 duk_push_number(ctx, (duk_double_t) du.d);
24185 break;
24186 default:
24187 DUK_UNREACHABLE();
24188 }
24189}
24190
24191/* Indexed write helper for buffer objects, also called from outside this file. */
24192DUK_INTERNAL void duk_hbufobj_validated_write(duk_context *ctx, duk_hbufobj *h_bufobj, duk_uint8_t *p, duk_small_uint_t elem_size) {
24194
24195 /* NOTE! Caller must ensure that any side effects from the
24196 * coercions below are safe. If that cannot be guaranteed
24197 * (which is normally the case), caller must coerce the
24198 * argument using duk_to_number() before any pointer
24199 * validations; the result of duk_to_number() always coerces
24200 * without side effects here.
24201 */
24202
24203 switch (h_bufobj->elem_type) {
24204 case DUK_HBUFOBJ_ELEM_UINT8:
24205 du.uc[0] = (duk_uint8_t) duk_to_uint32(ctx, -1);
24206 break;
24207 case DUK_HBUFOBJ_ELEM_UINT8CLAMPED:
24208 du.uc[0] = (duk_uint8_t) duk_to_uint8clamped(ctx, -1);
24209 break;
24210 case DUK_HBUFOBJ_ELEM_INT8:
24211 du.uc[0] = (duk_uint8_t) duk_to_int32(ctx, -1);
24212 break;
24213 case DUK_HBUFOBJ_ELEM_UINT16:
24214 du.us[0] = (duk_uint16_t) duk_to_uint32(ctx, -1);
24215 break;
24216 case DUK_HBUFOBJ_ELEM_INT16:
24217 du.us[0] = (duk_uint16_t) duk_to_int32(ctx, -1);
24218 break;
24219 case DUK_HBUFOBJ_ELEM_UINT32:
24220 du.ui[0] = (duk_uint32_t) duk_to_uint32(ctx, -1);
24221 break;
24222 case DUK_HBUFOBJ_ELEM_INT32:
24223 du.ui[0] = (duk_uint32_t) duk_to_int32(ctx, -1);
24224 break;
24225 case DUK_HBUFOBJ_ELEM_FLOAT32:
24226 du.f[0] = (duk_float_t) duk_to_number_m1(ctx);
24227 break;
24228 case DUK_HBUFOBJ_ELEM_FLOAT64:
24229 du.d = (duk_double_t) duk_to_number_m1(ctx);
24230 break;
24231 default:
24232 DUK_UNREACHABLE();
24233 }
24234
24235 DUK_MEMCPY((void *) p, (const void *) du.uc, (size_t) elem_size);
24236}
24237
24238/* Helper to create a fixed buffer from argument value at index 0.
24239 * Node.js and allocPlain() compatible.
24240 */
24241DUK_LOCAL duk_hbuffer *duk__hbufobj_fixed_from_argvalue(duk_context *ctx) {
24242 duk_int_t len;
24243 duk_int_t i;
24244 duk_size_t buf_size;
24245 duk_uint8_t *buf;
24246
24247 switch (duk_get_type(ctx, 0)) {
24248 case DUK_TYPE_NUMBER: {
24249 len = duk_to_int_clamped(ctx, 0, 0, DUK_INT_MAX);
24250 (void) duk_push_fixed_buffer_zero(ctx, (duk_size_t) len);
24251 break;
24252 }
24253 case DUK_TYPE_BUFFER: { /* Treat like Uint8Array. */
24254 goto slow_copy;
24255 }
24256 case DUK_TYPE_OBJECT: {
24257 duk_hobject *h;
24258 duk_hbufobj *h_bufobj;
24259
24260 /* For Node.js Buffers "Passing an ArrayBuffer returns a Buffer
24261 * that shares allocated memory with the given ArrayBuffer."
24262 * https://nodejs.org/api/buffer.html#buffer_buffer_from_buffer_alloc_and_buffer_allocunsafe
24263 */
24264
24265 h = duk_known_hobject(ctx, 0);
24266 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAYBUFFER) {
24267 DUK_ASSERT(DUK_HOBJECT_IS_BUFOBJ(h));
24268 h_bufobj = (duk_hbufobj *) h;
24269 if (DUK_UNLIKELY(h_bufobj->buf == NULL)) {
24270 DUK_ERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
24271 }
24272 if (DUK_UNLIKELY(h_bufobj->offset != 0 || h_bufobj->length != DUK_HBUFFER_GET_SIZE(h_bufobj->buf))) {
24273 /* No support for ArrayBuffers with slice
24274 * offset/length.
24275 */
24276 DUK_ERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
24277 }
24278 duk_push_hbuffer(ctx, h_bufobj->buf);
24279 return h_bufobj->buf;
24280 }
24281 goto slow_copy;
24282 }
24283 case DUK_TYPE_STRING: {
24284 /* ignore encoding for now */
24285 duk_require_hstring_notsymbol(ctx, 0);
24286 duk_dup_0(ctx);
24287 (void) duk_to_buffer(ctx, -1, &buf_size);
24288 break;
24289 }
24290 default:
24291 DUK_ERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
24292 }
24293
24294 done:
24295 DUK_ASSERT(duk_is_buffer(ctx, -1));
24296 return duk_known_hbuffer(ctx, -1);
24297
24298 slow_copy:
24299 /* XXX: fast path for typed arrays and other buffer objects? */
24300
24301 (void) duk_get_prop_stridx_short(ctx, 0, DUK_STRIDX_LENGTH);
24302 len = duk_to_int_clamped(ctx, -1, 0, DUK_INT_MAX);
24303 duk_pop(ctx);
24304 buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, (duk_size_t) len); /* no zeroing, all indices get initialized */
24305 for (i = 0; i < len; i++) {
24306 /* XXX: fast path for array or buffer arguments? */
24307 duk_get_prop_index(ctx, 0, (duk_uarridx_t) i);
24308 buf[i] = (duk_uint8_t) (duk_to_uint32(ctx, -1) & 0xffU);
24309 duk_pop(ctx);
24310 }
24311 goto done;
24312}
24313#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
24314
24315/*
24316 * Node.js Buffer constructor
24317 *
24318 * Node.js Buffers are just Uint8Arrays with internal prototype set to
24319 * Buffer.prototype so they're handled otherwise the same as Uint8Array.
24320 * However, the constructor arguments are very different so a separate
24321 * constructor entry point is used.
24322 */
24323#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
24324DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_constructor(duk_context *ctx) {
24325 duk_hbuffer *h_buf;
24326
24327 h_buf = duk__hbufobj_fixed_from_argvalue(ctx);
24328 DUK_ASSERT(h_buf != NULL);
24329
24330 duk_push_buffer_object(ctx,
24331 -1,
24332 0,
24333 DUK_HBUFFER_FIXED_GET_SIZE((duk_hbuffer_fixed *) h_buf),
24334 DUK_BUFOBJ_UINT8ARRAY);
24335 duk_push_hobject_bidx(ctx, DUK_BIDX_NODEJS_BUFFER_PROTOTYPE);
24336 duk_set_prototype(ctx, -2);
24337
24338 /* XXX: a more direct implementation */
24339
24340 return 1;
24341}
24342#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
24343
24344/*
24345 * ArrayBuffer, DataView, and TypedArray constructors
24346 */
24347
24348#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
24349DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_constructor(duk_context *ctx) {
24350 duk_hthread *thr;
24351 duk_hbufobj *h_bufobj;
24352 duk_hbuffer *h_val;
24353 duk_int_t len;
24354
24355 DUK_ASSERT_CTX_VALID(ctx);
24356 thr = (duk_hthread *) ctx;
24357 DUK_UNREF(thr);
24358
24359 duk_require_constructor_call(ctx);
24360
24361 len = duk_to_int(ctx, 0);
24362 if (len < 0) {
24363 goto fail_length;
24364 }
24365 (void) duk_push_fixed_buffer_zero(ctx, (duk_size_t) len);
24366 h_val = (duk_hbuffer *) duk_known_hbuffer(ctx, -1);
24367
24368 h_bufobj = duk_push_bufobj_raw(ctx,
24369 DUK_HOBJECT_FLAG_EXTENSIBLE |
24370 DUK_HOBJECT_FLAG_BUFOBJ |
24371 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
24372 DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
24373 DUK_ASSERT(h_bufobj != NULL);
24374
24375 duk__set_bufobj_buffer(ctx, h_bufobj, h_val);
24376 DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
24377
24378 return 1;
24379
24380 fail_length:
24381 DUK_DCERROR_RANGE_INVALID_LENGTH(thr);
24382}
24383#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
24384
24385
24386/* Format of magic, bits:
24387 * 0...1: elem size shift (0-3)
24388 * 2...5: elem type (DUK_HBUFOBJ_ELEM_xxx)
24389 *
24390 * XXX: add prototype bidx explicitly to magic instead of using a mapping?
24391 */
24392
24393#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
24394DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
24395 duk_hthread *thr;
24396 duk_tval *tv;
24397 duk_hobject *h_obj;
24398 duk_hbufobj *h_bufobj = NULL;
24399 duk_hbufobj *h_bufarr = NULL;
24400 duk_hbufobj *h_bufarg = NULL;
24401 duk_hbuffer *h_val;
24402 duk_small_uint_t magic;
24403 duk_small_uint_t shift;
24404 duk_small_uint_t elem_type;
24405 duk_small_uint_t elem_size;
24406 duk_small_uint_t class_num;
24407 duk_small_uint_t proto_bidx;
24408 duk_uint_t align_mask;
24409 duk_uint_t elem_length;
24410 duk_int_t elem_length_signed;
24411 duk_uint_t byte_length;
24412 duk_small_uint_t copy_mode;
24413
24414 thr = (duk_hthread *) ctx;
24415 DUK_UNREF(thr);
24416
24417 /* XXX: The same copy helpers could be shared with at least some
24418 * buffer functions.
24419 */
24420
24421 duk_require_constructor_call(ctx);
24422
24423 /* We could fit built-in index into magic but that'd make the magic
24424 * number dependent on built-in numbering (genbuiltins.py doesn't
24425 * handle that yet). So map both class and prototype from the
24426 * element type.
24427 */
24428 magic = duk_get_current_magic(ctx);
24429 shift = magic & 0x03; /* bits 0...1: shift */
24430 elem_type = (magic >> 2) & 0x0f; /* bits 2...5: type */
24431 elem_size = 1 << shift;
24432 align_mask = elem_size - 1;
24433 DUK_ASSERT(elem_type < sizeof(duk__buffer_proto_from_elemtype) / sizeof(duk_uint8_t));
24434 proto_bidx = duk__buffer_proto_from_elemtype[elem_type];
24435 DUK_ASSERT(proto_bidx < DUK_NUM_BUILTINS);
24436 DUK_ASSERT(elem_type < sizeof(duk__buffer_class_from_elemtype) / sizeof(duk_uint8_t));
24437 class_num = duk__buffer_class_from_elemtype[elem_type];
24438
24439 DUK_DD(DUK_DDPRINT("typedarray constructor, magic=%d, shift=%d, elem_type=%d, "
24440 "elem_size=%d, proto_bidx=%d, class_num=%d",
24441 (int) magic, (int) shift, (int) elem_type, (int) elem_size,
24442 (int) proto_bidx, (int) class_num));
24443
24444 /* Argument variants. When the argument is an ArrayBuffer a view to
24445 * the same buffer is created; otherwise a new ArrayBuffer is always
24446 * created.
24447 */
24448
24449 /* XXX: initial iteration to treat a plain buffer like an ArrayBuffer:
24450 * coerce to an ArrayBuffer object and use that as .buffer. The underlying
24451 * buffer will be the same but result .buffer !== inputPlainBuffer.
24452 */
24453 duk_hbufobj_promote_plain(ctx, 0);
24454
24455 tv = duk_get_tval(ctx, 0);
24456 DUK_ASSERT(tv != NULL); /* arg count */
24457 if (DUK_TVAL_IS_OBJECT(tv)) {
24458 h_obj = DUK_TVAL_GET_OBJECT(tv);
24459 DUK_ASSERT(h_obj != NULL);
24460
24461 if (DUK_HOBJECT_GET_CLASS_NUMBER(h_obj) == DUK_HOBJECT_CLASS_ARRAYBUFFER) {
24462 /* ArrayBuffer: unlike any other argument variant, create
24463 * a view into the existing buffer.
24464 */
24465
24466 duk_int_t byte_offset_signed;
24467 duk_uint_t byte_offset;
24468
24469 h_bufarg = (duk_hbufobj *) h_obj;
24470
24471 byte_offset_signed = duk_to_int(ctx, 1);
24472 if (byte_offset_signed < 0) {
24473 goto fail_arguments;
24474 }
24475 byte_offset = (duk_uint_t) byte_offset_signed;
24476 if (byte_offset > h_bufarg->length ||
24477 (byte_offset & align_mask) != 0) {
24478 /* Must be >= 0 and multiple of element size. */
24479 goto fail_arguments;
24480 }
24481 if (duk_is_undefined(ctx, 2)) {
24482 DUK_ASSERT(h_bufarg->length >= byte_offset);
24483 byte_length = h_bufarg->length - byte_offset;
24484 if ((byte_length & align_mask) != 0) {
24485 /* Must be element size multiple from
24486 * start offset to end of buffer.
24487 */
24488 goto fail_arguments;
24489 }
24490 elem_length = (byte_length >> shift);
24491 } else {
24492 elem_length_signed = duk_to_int(ctx, 2);
24493 if (elem_length_signed < 0) {
24494 goto fail_arguments;
24495 }
24496 elem_length = (duk_uint_t) elem_length_signed;
24497 byte_length = elem_length << shift;
24498 if ((byte_length >> shift) != elem_length) {
24499 /* Byte length would overflow. */
24500 /* XXX: easier check with less code? */
24501 goto fail_arguments;
24502 }
24503 DUK_ASSERT(h_bufarg->length >= byte_offset);
24504 if (byte_length > h_bufarg->length - byte_offset) {
24505 /* Not enough data. */
24506 goto fail_arguments;
24507 }
24508 }
24509 DUK_UNREF(elem_length);
24510 DUK_ASSERT_DISABLE(byte_offset >= 0);
24511 DUK_ASSERT(byte_offset <= h_bufarg->length);
24512 DUK_ASSERT_DISABLE(byte_length >= 0);
24513 DUK_ASSERT(byte_offset + byte_length <= h_bufarg->length);
24514 DUK_ASSERT((elem_length << shift) == byte_length);
24515
24516 h_bufobj = duk_push_bufobj_raw(ctx,
24517 DUK_HOBJECT_FLAG_EXTENSIBLE |
24518 DUK_HOBJECT_FLAG_BUFOBJ |
24519 DUK_HOBJECT_CLASS_AS_FLAGS(class_num),
24520 proto_bidx);
24521 h_val = h_bufarg->buf;
24522 if (h_val == NULL) {
24523 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
24524 }
24525 h_bufobj->buf = h_val;
24526 DUK_HBUFFER_INCREF(thr, h_val);
24527 h_bufobj->offset = h_bufarg->offset + byte_offset;
24528 h_bufobj->length = byte_length;
24529 h_bufobj->shift = (duk_uint8_t) shift;
24530 h_bufobj->elem_type = (duk_uint8_t) elem_type;
24531 h_bufobj->is_typedarray = 1;
24532 DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
24533
24534 /* Set .buffer to the argument ArrayBuffer. */
24535 DUK_ASSERT(h_bufobj->buf_prop == NULL);
24536 h_bufobj->buf_prop = (duk_hobject *) h_bufarg;
24537 DUK_ASSERT(h_bufarg != NULL);
24538 DUK_HBUFOBJ_INCREF(thr, h_bufarg);
24539 return 1;
24540 } else if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
24541 /* TypedArray (or other non-ArrayBuffer duk_hbufobj).
24542 * Conceptually same behavior as for an Array-like argument,
24543 * with a few fast paths.
24544 */
24545
24546 h_bufarg = (duk_hbufobj *) h_obj;
24547 DUK_ASSERT_HBUFOBJ_VALID(h_bufarg);
24548 elem_length_signed = (duk_int_t) (h_bufarg->length >> h_bufarg->shift);
24549 if (h_bufarg->buf == NULL) {
24550 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
24551 }
24552
24553 /* Select copy mode. Must take into account element
24554 * compatibility and validity of the underlying source
24555 * buffer.
24556 */
24557
24558 DUK_DDD(DUK_DDDPRINT("selecting copy mode for bufobj arg, "
24559 "src byte_length=%ld, src shift=%d, "
24560 "src/dst elem_length=%ld; "
24561 "dst shift=%d -> dst byte_length=%ld",
24562 (long) h_bufarg->length, (int) h_bufarg->shift,
24563 (long) elem_length_signed, (int) shift,
24564 (long) (elem_length_signed << shift)));
24565
24566 copy_mode = 2; /* default is explicit index read/write copy */
24567#if !defined(DUK_USE_PREFER_SIZE)
24568 /* With a size optimized build copy_mode 2 is enough.
24569 * Modes 0 and 1 are faster but conceptually the same.
24570 */
24571 DUK_ASSERT(elem_type < sizeof(duk__buffer_elemtype_copy_compatible) / sizeof(duk_uint16_t));
24572 if (DUK_HBUFOBJ_VALID_SLICE(h_bufarg)) {
24573 if ((duk__buffer_elemtype_copy_compatible[elem_type] & (1 << h_bufarg->elem_type)) != 0) {
24574 DUK_DDD(DUK_DDDPRINT("source/target are copy compatible, memcpy"));
24575 DUK_ASSERT(shift == h_bufarg->shift); /* byte sizes will match */
24576 copy_mode = 0;
24577 } else {
24578 DUK_DDD(DUK_DDDPRINT("source/target not copy compatible but valid, fast copy"));
24579 copy_mode = 1;
24580 }
24581 }
24582#endif /* !DUK_USE_PREFER_SIZE */
24583 } else {
24584 /* Array or Array-like */
24585 elem_length_signed = (duk_int_t) duk_get_length(ctx, 0);
24586 copy_mode = 2;
24587 }
24588 } else {
24589 /* Non-object argument is simply int coerced, matches
24590 * V8 behavior (except for "null", which we coerce to
24591 * 0 but V8 TypeErrors).
24592 */
24593 elem_length_signed = duk_to_int(ctx, 0);
24594 copy_mode = 3;
24595 }
24596 if (elem_length_signed < 0) {
24597 goto fail_arguments;
24598 }
24599 elem_length = (duk_uint_t) elem_length_signed;
24600 byte_length = (duk_uint_t) (elem_length << shift);
24601 if ((byte_length >> shift) != elem_length) {
24602 /* Byte length would overflow. */
24603 /* XXX: easier check with less code? */
24604 goto fail_arguments;
24605 }
24606
24607 DUK_DDD(DUK_DDDPRINT("elem_length=%ld, byte_length=%ld",
24608 (long) elem_length, (long) byte_length));
24609
24610 /* ArrayBuffer argument is handled specially above; the rest of the
24611 * argument variants are handled by shared code below.
24612 */
24613
24614 /* Push a new ArrayBuffer (becomes view .buffer) */
24615 h_bufarr = duk__push_arraybuffer_with_length(ctx, byte_length);
24616 DUK_ASSERT(h_bufarr != NULL);
24617 h_val = h_bufarr->buf;
24618 DUK_ASSERT(h_val != NULL);
24619
24620 /* Push the resulting view object and attach the ArrayBuffer. */
24621 h_bufobj = duk_push_bufobj_raw(ctx,
24622 DUK_HOBJECT_FLAG_EXTENSIBLE |
24623 DUK_HOBJECT_FLAG_BUFOBJ |
24624 DUK_HOBJECT_CLASS_AS_FLAGS(class_num),
24625 proto_bidx);
24626
24627 h_bufobj->buf = h_val;
24628 DUK_HBUFFER_INCREF(thr, h_val);
24629 DUK_ASSERT(h_bufobj->offset == 0);
24630 h_bufobj->length = byte_length;
24631 h_bufobj->shift = (duk_uint8_t) shift;
24632 h_bufobj->elem_type = (duk_uint8_t) elem_type;
24633 h_bufobj->is_typedarray = 1;
24634 DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
24635
24636 /* Set .buffer */
24637 DUK_ASSERT(h_bufobj->buf_prop == NULL);
24638 h_bufobj->buf_prop = (duk_hobject *) h_bufarr;
24639 DUK_ASSERT(h_bufarr != NULL);
24640 DUK_HBUFOBJ_INCREF(thr, h_bufarr);
24641
24642 /* Copy values, the copy method depends on the arguments.
24643 *
24644 * Copy mode decision may depend on the validity of the underlying
24645 * buffer of the source argument; there must be no harmful side effects
24646 * from there to here for copy_mode to still be valid.
24647 */
24648 DUK_DDD(DUK_DDDPRINT("copy mode: %d", (int) copy_mode));
24649 switch (copy_mode) {
24650 /* Copy modes 0 and 1 can be omitted in size optimized build,
24651 * copy mode 2 handles them (but more slowly).
24652 */
24653#if !defined(DUK_USE_PREFER_SIZE)
24654 case 0: {
24655 /* Use byte copy. */
24656
24657 duk_uint8_t *p_src;
24658 duk_uint8_t *p_dst;
24659
24660 DUK_ASSERT(h_bufobj != NULL);
24661 DUK_ASSERT(h_bufobj->buf != NULL);
24662 DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufobj));
24663 DUK_ASSERT(h_bufarg != NULL);
24664 DUK_ASSERT(h_bufarg->buf != NULL);
24665 DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufarg));
24666
24667 p_dst = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj);
24668 p_src = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg);
24669
24670 DUK_DDD(DUK_DDDPRINT("using memcpy: p_src=%p, p_dst=%p, byte_length=%ld",
24671 (void *) p_src, (void *) p_dst, (long) byte_length));
24672
24673 DUK_MEMCPY((void *) p_dst, (const void *) p_src, (size_t) byte_length);
24674 break;
24675 }
24676 case 1: {
24677 /* Copy values through direct validated reads and writes. */
24678
24679 duk_small_uint_t src_elem_size;
24680 duk_small_uint_t dst_elem_size;
24681 duk_uint8_t *p_src;
24682 duk_uint8_t *p_src_end;
24683 duk_uint8_t *p_dst;
24684
24685 DUK_ASSERT(h_bufobj != NULL);
24686 DUK_ASSERT(h_bufobj->buf != NULL);
24687 DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufobj));
24688 DUK_ASSERT(h_bufarg != NULL);
24689 DUK_ASSERT(h_bufarg->buf != NULL);
24690 DUK_ASSERT(DUK_HBUFOBJ_VALID_SLICE(h_bufarg));
24691
24692 src_elem_size = 1 << h_bufarg->shift;
24693 dst_elem_size = elem_size;
24694
24695 p_src = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg);
24696 p_dst = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj);
24697 p_src_end = p_src + h_bufarg->length;
24698
24699 DUK_DDD(DUK_DDDPRINT("using fast copy: p_src=%p, p_src_end=%p, p_dst=%p, "
24700 "src_elem_size=%d, dst_elem_size=%d",
24701 (void *) p_src, (void *) p_src_end, (void *) p_dst,
24702 (int) src_elem_size, (int) dst_elem_size));
24703
24704 while (p_src != p_src_end) {
24705 DUK_DDD(DUK_DDDPRINT("fast path per element copy loop: "
24706 "p_src=%p, p_src_end=%p, p_dst=%p",
24707 (void *) p_src, (void *) p_src_end, (void *) p_dst));
24708 /* A validated read() is always a number, so it's write coercion
24709 * is always side effect free an won't invalidate pointers etc.
24710 */
24711 duk_hbufobj_push_validated_read(ctx, h_bufarg, p_src, src_elem_size);
24712 duk_hbufobj_validated_write(ctx, h_bufobj, p_dst, dst_elem_size);
24713 duk_pop(ctx);
24714 p_src += src_elem_size;
24715 p_dst += dst_elem_size;
24716 }
24717 break;
24718 }
24719#endif /* !DUK_USE_PREFER_SIZE */
24720 case 2: {
24721 /* Copy values by index reads and writes. Let virtual
24722 * property handling take care of coercion.
24723 */
24724 duk_uint_t i;
24725
24726 DUK_DDD(DUK_DDDPRINT("using slow copy"));
24727
24728 for (i = 0; i < elem_length; i++) {
24729 duk_get_prop_index(ctx, 0, (duk_uarridx_t) i);
24730 duk_put_prop_index(ctx, -2, (duk_uarridx_t) i);
24731 }
24732 break;
24733 }
24734 default:
24735 case 3: {
24736 /* No copy, leave zero bytes in the buffer. There's no
24737 * ambiguity with Float32/Float64 because zero bytes also
24738 * represent 0.0.
24739 */
24740
24741 DUK_DDD(DUK_DDDPRINT("using no copy"));
24742 break;
24743 }
24744 }
24745
24746 return 1;
24747
24748 fail_arguments:
24749 DUK_DCERROR_RANGE_INVALID_ARGS(thr);
24750}
24751#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
24752/* When bufferobject support is disabled, new Uint8Array() could still be
24753 * supported to create a plain fixed buffer. Disabled for now.
24754 */
24755#if 0
24756DUK_INTERNAL duk_ret_t duk_bi_typedarray_constructor(duk_context *ctx) {
24757 duk_int_t elem_length_signed;
24758 duk_uint_t byte_length;
24759
24760 /* XXX: The same copy helpers could be shared with at least some
24761 * buffer functions.
24762 */
24763
24764 duk_require_constructor_call(ctx);
24765
24766 elem_length_signed = duk_require_int(ctx, 0);
24767 if (elem_length_signed < 0) {
24768 goto fail_arguments;
24769 }
24770 byte_length = (duk_uint_t) elem_length_signed;
24771
24772 (void) duk_push_fixed_buffer_zero(ctx, (duk_size_t) byte_length);
24773 return 1;
24774
24775 fail_arguments:
24776 DUK_DCERROR_RANGE_INVALID_ARGS((duk_hthread *) ctx);
24777}
24778#endif /* 0 */
24779#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
24780
24781#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
24782DUK_INTERNAL duk_ret_t duk_bi_dataview_constructor(duk_context *ctx) {
24783 duk_hbufobj *h_bufarg;
24784 duk_hbufobj *h_bufobj;
24785 duk_hbuffer *h_val;
24786 duk_uint_t offset;
24787 duk_uint_t length;
24788
24789 duk_require_constructor_call(ctx);
24790
24791 h_bufarg = duk__require_bufobj_value(ctx, 0);
24792 DUK_ASSERT(h_bufarg != NULL);
24793 if (DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_bufarg) != DUK_HOBJECT_CLASS_ARRAYBUFFER) {
24794 DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
24795 }
24796
24797 duk__resolve_offset_opt_length(ctx, h_bufarg, 1, 2, &offset, &length, 1 /*throw_flag*/);
24798 DUK_ASSERT(offset <= h_bufarg->length);
24799 DUK_ASSERT(offset + length <= h_bufarg->length);
24800
24801 h_bufobj = duk_push_bufobj_raw(ctx,
24802 DUK_HOBJECT_FLAG_EXTENSIBLE |
24803 DUK_HOBJECT_FLAG_BUFOBJ |
24804 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATAVIEW),
24805 DUK_BIDX_DATAVIEW_PROTOTYPE);
24806
24807 h_val = h_bufarg->buf;
24808 if (h_val == NULL) {
24809 DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
24810 }
24811 h_bufobj->buf = h_val;
24812 DUK_HBUFFER_INCREF(thr, h_val);
24813 h_bufobj->offset = h_bufarg->offset + offset;
24814 h_bufobj->length = length;
24815 DUK_ASSERT(h_bufobj->shift == 0);
24816 DUK_ASSERT(h_bufobj->elem_type == DUK_HBUFOBJ_ELEM_UINT8);
24817 DUK_ASSERT(h_bufobj->is_typedarray == 0);
24818
24819 DUK_ASSERT(h_bufobj->buf_prop == NULL);
24820 h_bufobj->buf_prop = (duk_hobject *) h_bufarg;
24821 DUK_ASSERT(h_bufarg != NULL);
24822 DUK_HBUFOBJ_INCREF((duk_hthread *) ctx, h_bufarg);
24823
24824 DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
24825 return 1;
24826}
24827#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
24828
24829/*
24830 * ArrayBuffer.isView()
24831 */
24832
24833#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
24834DUK_INTERNAL duk_ret_t duk_bi_arraybuffer_isview(duk_context *ctx) {
24835 duk_hobject *h_obj;
24836 duk_bool_t ret = 0;
24837
24838 if (duk_is_buffer(ctx, 0)) {
24839 ret = 1;
24840 } else {
24841 h_obj = duk_get_hobject(ctx, 0);
24842 if (h_obj != NULL && DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
24843 /* DataView needs special casing: ArrayBuffer.isView() is
24844 * true, but ->is_typedarray is 0.
24845 */
24846 ret = ((duk_hbufobj *) h_obj)->is_typedarray ||
24847 (DUK_HOBJECT_GET_CLASS_NUMBER(h_obj) == DUK_HOBJECT_CLASS_DATAVIEW);
24848 }
24849 }
24850 duk_push_boolean(ctx, ret);
24851 return 1;
24852}
24853#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
24854
24855/*
24856 * Uint8Array.allocPlain()
24857 */
24858
24859#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
24860DUK_INTERNAL duk_ret_t duk_bi_uint8array_allocplain(duk_context *ctx) {
24861 duk__hbufobj_fixed_from_argvalue(ctx);
24862 return 1;
24863}
24864#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
24865
24866/*
24867 * Uint8Array.plainOf()
24868 */
24869
24870#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
24871DUK_INTERNAL duk_ret_t duk_bi_uint8array_plainof(duk_context *ctx) {
24872 duk_hbufobj *h_bufobj;
24873
24874#if !defined(DUK_USE_PREFER_SIZE)
24875 /* Avoid churn if argument is already a plain buffer. */
24876 if (duk_is_buffer(ctx, 0)) {
24877 return 1;
24878 }
24879#endif
24880
24881 /* Promotes plain buffers to ArrayBuffers, so for a plain buffer
24882 * argument we'll create a pointless temporary (but still work
24883 * correctly).
24884 */
24885 h_bufobj = duk__require_bufobj_value(ctx, 0);
24886 if (h_bufobj->buf == NULL) {
24887 duk_push_undefined(ctx);
24888 } else {
24889 duk_push_hbuffer(ctx, h_bufobj->buf);
24890 }
24891 return 1;
24892}
24893#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
24894
24895/*
24896 * Node.js Buffer: toString([encoding], [start], [end])
24897 */
24898
24899#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
24900DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tostring(duk_context *ctx) {
24901 duk_hthread *thr;
24902 duk_hbufobj *h_this;
24903 duk_int_t start_offset, end_offset;
24904 duk_uint8_t *buf_slice;
24905 duk_size_t slice_length;
24906
24907 thr = (duk_hthread *) ctx;
24908 DUK_UNREF(thr);
24909
24910 h_this = duk__get_bufobj_this(ctx);
24911 if (h_this == NULL) {
24912 /* XXX: happens e.g. when evaluating: String(Buffer.prototype). */
24913 duk_push_string(ctx, "[object Object]");
24914 return 1;
24915 }
24916 DUK_ASSERT_HBUFOBJ_VALID(h_this);
24917
24918 /* Ignore encoding for now. */
24919
24920 duk__clamp_startend_nonegidx_noshift(ctx,
24921 (duk_int_t) h_this->length,
24922 1 /*idx_start*/,
24923 2 /*idx_end*/,
24924 &start_offset,
24925 &end_offset);
24926
24927 slice_length = (duk_size_t) (end_offset - start_offset);
24928 buf_slice = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, slice_length); /* all bytes initialized below */
24929 DUK_ASSERT(buf_slice != NULL);
24930
24931 /* Neutered or uncovered, TypeError. */
24932 if (h_this->buf == NULL ||
24933 !DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, start_offset + slice_length)) {
24934 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
24935 }
24936
24937 /* XXX: ideally we wouldn't make a copy but a view into the buffer for the
24938 * decoding process. Or the decoding helper could be changed to accept
24939 * the slice info (a buffer pointer is NOT a good approach because guaranteeing
24940 * its stability is difficult).
24941 */
24942
24943 DUK_ASSERT(DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, start_offset + slice_length));
24944 DUK_MEMCPY((void *) buf_slice,
24945 (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
24946 (size_t) slice_length);
24947
24948 /* Use the equivalent of: new TextEncoder().encode(this) to convert the
24949 * string. Result will be valid UTF-8; non-CESU-8 inputs are currently
24950 * interpreted loosely. Value stack convention is a bit odd for now.
24951 */
24952 duk_replace(ctx, 0);
24953 duk_set_top(ctx, 1);
24954 return duk_textdecoder_decode_utf8_nodejs(ctx);
24955}
24956#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
24957
24958/*
24959 * Node.js Buffer.prototype: toJSON()
24960 */
24961
24962#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
24963DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_tojson(duk_context *ctx) {
24964 duk_hthread *thr;
24965 duk_hbufobj *h_this;
24966 duk_harray *h_arr;
24967 duk_uint8_t *buf;
24968 duk_uint_t i, n;
24969 duk_tval *tv;
24970
24971 thr = (duk_hthread *) ctx;
24972 DUK_UNREF(thr);
24973
24974 h_this = duk__require_bufobj_this(ctx);
24975 DUK_ASSERT(h_this != NULL);
24976
24977 if (h_this->buf == NULL || !DUK_HBUFOBJ_VALID_SLICE(h_this)) {
24978 /* Serialize uncovered backing buffer as a null; doesn't
24979 * really matter as long we're memory safe.
24980 */
24981 duk_push_null(ctx);
24982 return 1;
24983 }
24984
24985 duk_push_object(ctx);
24986 duk_push_hstring_stridx(ctx, DUK_STRIDX_UC_BUFFER);
24987 duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_TYPE);
24988
24989 DUK_ASSERT_DISABLE((duk_size_t) h_this->length <= (duk_size_t) DUK_UINT32_MAX);
24990 h_arr = duk_push_harray_with_size(ctx, (duk_uint32_t) h_this->length); /* XXX: needs revision with >4G buffers */
24991 DUK_ASSERT(h_arr != NULL);
24992 DUK_ASSERT(h_arr->length == h_this->length);
24993 tv = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) h_arr);
24994
24995 DUK_ASSERT(h_this->buf != NULL);
24996 buf = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this);
24997 for (i = 0, n = h_this->length; i < n; i++) {
24998 DUK_TVAL_SET_U32(tv + i, (duk_uint32_t) buf[i]); /* no need for decref or incref */
24999 }
25000 duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_DATA);
25001
25002 return 1;
25003}
25004#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
25005
25006/*
25007 * Node.js Buffer.prototype.equals()
25008 * Node.js Buffer.prototype.compare()
25009 * Node.js Buffer.compare()
25010 */
25011
25012#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
25013DUK_INTERNAL duk_ret_t duk_bi_buffer_compare_shared(duk_context *ctx) {
25014 duk_hthread *thr;
25015 duk_small_uint_t magic;
25016 duk_hbufobj *h_bufarg1;
25017 duk_hbufobj *h_bufarg2;
25018 duk_small_int_t comp_res;
25019
25020 thr = (duk_hthread *) ctx;
25021 DUK_UNREF(thr);
25022
25023 /* XXX: keep support for plain buffers and non-Node.js buffers? */
25024
25025 magic = duk_get_current_magic(ctx);
25026 if (magic & 0x02) {
25027 /* Static call style. */
25028 h_bufarg1 = duk__require_bufobj_value(ctx, 0);
25029 h_bufarg2 = duk__require_bufobj_value(ctx, 1);
25030 } else {
25031 h_bufarg1 = duk__require_bufobj_this(ctx);
25032 h_bufarg2 = duk__require_bufobj_value(ctx, 0);
25033 }
25034 DUK_ASSERT(h_bufarg1 != NULL);
25035 DUK_ASSERT(h_bufarg2 != NULL);
25036
25037 /* We want to compare the slice/view areas of the arguments.
25038 * If either slice/view is invalid (underlying buffer is shorter)
25039 * ensure equals() is false, but otherwise the only thing that
25040 * matters is to be memory safe.
25041 */
25042
25043 if (DUK_HBUFOBJ_VALID_SLICE(h_bufarg1) &&
25044 DUK_HBUFOBJ_VALID_SLICE(h_bufarg2)) {
25045 comp_res = duk_js_data_compare((const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufarg1->buf) + h_bufarg1->offset,
25046 (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufarg2->buf) + h_bufarg2->offset,
25047 (duk_size_t) h_bufarg1->length,
25048 (duk_size_t) h_bufarg2->length);
25049 } else {
25050 comp_res = -1; /* either nonzero value is ok */
25051 }
25052
25053 if (magic & 0x01) {
25054 /* compare: similar to string comparison but for buffer data. */
25055 duk_push_int(ctx, comp_res);
25056 } else {
25057 /* equals */
25058 duk_push_boolean(ctx, (comp_res == 0));
25059 }
25060
25061 return 1;
25062}
25063#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
25064
25065/*
25066 * Node.js Buffer.prototype.fill()
25067 */
25068
25069#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
25070DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_fill(duk_context *ctx) {
25071 duk_hthread *thr;
25072 duk_hbufobj *h_this;
25073 const duk_uint8_t *fill_str_ptr;
25074 duk_size_t fill_str_len;
25075 duk_uint8_t fill_value;
25076 duk_int_t fill_offset;
25077 duk_int_t fill_end;
25078 duk_size_t fill_length;
25079 duk_uint8_t *p;
25080
25081 thr = (duk_hthread *) ctx;
25082 DUK_UNREF(thr);
25083
25084 h_this = duk__require_bufobj_this(ctx);
25085 DUK_ASSERT(h_this != NULL);
25086 if (h_this->buf == NULL) {
25087 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
25088 }
25089
25090 /* [ value offset end ] */
25091
25092 if (duk_is_string_notsymbol(ctx, 0)) {
25093 fill_str_ptr = (const duk_uint8_t *) duk_get_lstring(ctx, 0, &fill_str_len);
25094 DUK_ASSERT(fill_str_ptr != NULL);
25095 } else {
25096 /* Symbols get ToNumber() coerced and cause TypeError. */
25097 fill_value = (duk_uint8_t) duk_to_uint32(ctx, 0);
25098 fill_str_ptr = (const duk_uint8_t *) &fill_value;
25099 fill_str_len = 1;
25100 }
25101
25102 /* Fill offset handling is more lenient than in Node.js. */
25103
25104 duk__clamp_startend_nonegidx_noshift(ctx,
25105 (duk_int_t) h_this->length,
25106 1 /*idx_start*/,
25107 2 /*idx_end*/,
25108 &fill_offset,
25109 &fill_end);
25110
25111 DUK_DDD(DUK_DDDPRINT("fill: fill_value=%02x, fill_offset=%ld, fill_end=%ld, view length=%ld",
25112 (unsigned int) fill_value, (long) fill_offset, (long) fill_end, (long) h_this->length));
25113
25114 DUK_ASSERT(fill_end - fill_offset >= 0);
25115 DUK_ASSERT(h_this->buf != NULL);
25116
25117 p = (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + fill_offset);
25118 fill_length = (duk_size_t) (fill_end - fill_offset);
25119 if (fill_str_len == 1) {
25120 /* Handle single character fills as memset() even when
25121 * the fill data comes from a one-char argument.
25122 */
25123 DUK_MEMSET((void *) p, (int) fill_str_ptr[0], (size_t) fill_length);
25124 } else if (fill_str_len > 1) {
25125 duk_size_t i, n, t;
25126
25127 for (i = 0, n = (fill_end - fill_offset), t = 0; i < n; i++) {
25128 p[i] = fill_str_ptr[t++];
25129 if (t >= fill_str_len) {
25130 t = 0;
25131 }
25132 }
25133 } else {
25134 DUK_DDD(DUK_DDDPRINT("zero size fill pattern, ignore silently"));
25135 }
25136
25137 /* Return the Buffer to allow chaining: b.fill(0x11).fill(0x22, 3, 5).toString() */
25138 duk_push_this(ctx);
25139 return 1;
25140}
25141#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
25142
25143/*
25144 * Node.js Buffer.prototype.write(string, [offset], [length], [encoding])
25145 */
25146
25147#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
25148DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_write(duk_context *ctx) {
25149 duk_hthread *thr;
25150 duk_hbufobj *h_this;
25151 duk_uint_t offset;
25152 duk_uint_t length;
25153 const duk_uint8_t *str_data;
25154 duk_size_t str_len;
25155
25156 thr = (duk_hthread *) ctx;
25157 DUK_UNREF(thr);
25158
25159 /* XXX: very inefficient support for plain buffers */
25160 h_this = duk__require_bufobj_this(ctx);
25161 DUK_ASSERT(h_this != NULL);
25162
25163 /* Argument must be a string, e.g. a buffer is not allowed. */
25164 str_data = (const duk_uint8_t *) duk_require_lstring_notsymbol(ctx, 0, &str_len);
25165
25166 duk__resolve_offset_opt_length(ctx, h_this, 1, 2, &offset, &length, 0 /*throw_flag*/);
25167 DUK_ASSERT(offset <= h_this->length);
25168 DUK_ASSERT(offset + length <= h_this->length);
25169
25170 /* XXX: encoding is ignored now. */
25171
25172 if (length > str_len) {
25173 length = (duk_uint_t) str_len;
25174 }
25175
25176 if (DUK_HBUFOBJ_VALID_SLICE(h_this)) {
25177 /* Cannot overlap. */
25178 DUK_MEMCPY((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + offset),
25179 (const void *) str_data,
25180 (size_t) length);
25181 } else {
25182 DUK_DDD(DUK_DDDPRINT("write() target buffer is not covered, silent ignore"));
25183 }
25184
25185 duk_push_uint(ctx, length);
25186 return 1;
25187}
25188#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
25189
25190/*
25191 * Node.js Buffer.prototype.copy()
25192 */
25193
25194#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
25195DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_copy(duk_context *ctx) {
25196 duk_hthread *thr;
25197 duk_hbufobj *h_this;
25198 duk_hbufobj *h_bufarg;
25199 duk_int_t source_length;
25200 duk_int_t target_length;
25201 duk_int_t target_start, source_start, source_end;
25202 duk_uint_t target_ustart, source_ustart, source_uend;
25203 duk_uint_t copy_size = 0;
25204
25205 /* [ targetBuffer targetStart sourceStart sourceEnd ] */
25206
25207 thr = (duk_hthread *) ctx;
25208 DUK_UNREF(thr);
25209
25210 h_this = duk__require_bufobj_this(ctx);
25211 h_bufarg = duk__require_bufobj_value(ctx, 0);
25212 DUK_ASSERT(h_this != NULL);
25213 DUK_ASSERT(h_bufarg != NULL);
25214 source_length = (duk_int_t) h_this->length;
25215 target_length = (duk_int_t) h_bufarg->length;
25216
25217 target_start = duk_to_int(ctx, 1);
25218 source_start = duk_to_int(ctx, 2);
25219 if (duk_is_undefined(ctx, 3)) {
25220 source_end = source_length;
25221 } else {
25222 source_end = duk_to_int(ctx, 3);
25223 }
25224
25225 DUK_DDD(DUK_DDDPRINT("checking copy args: target_start=%ld, target_length=%ld, "
25226 "source_start=%ld, source_end=%ld, source_length=%ld",
25227 (long) target_start, (long) h_bufarg->length,
25228 (long) source_start, (long) source_end, (long) source_length));
25229
25230 /* This behavior mostly mimics Node.js now. */
25231
25232 if (source_start < 0 || source_end < 0 || target_start < 0) {
25233 /* Negative offsets cause a RangeError. */
25234 goto fail_bounds;
25235 }
25236 source_ustart = (duk_uint_t) source_start;
25237 source_uend = (duk_uint_t) source_end;
25238 target_ustart = (duk_uint_t) target_start;
25239 if (source_ustart >= source_uend || /* crossed offsets or zero size */
25240 source_ustart >= (duk_uint_t) source_length || /* source out-of-bounds (but positive) */
25241 target_ustart >= (duk_uint_t) target_length) { /* target out-of-bounds (but positive) */
25242 goto silent_ignore;
25243 }
25244 if (source_uend >= (duk_uint_t) source_length) {
25245 /* Source end clamped silently to available length. */
25246 source_uend = source_length;
25247 }
25248 copy_size = source_uend - source_ustart;
25249 if (target_ustart + copy_size > (duk_uint_t) target_length) {
25250 /* Clamp to target's end if too long.
25251 *
25252 * NOTE: there's no overflow possibility in the comparison;
25253 * both target_ustart and copy_size are >= 0 and based on
25254 * values in duk_int_t range. Adding them as duk_uint_t
25255 * values is then guaranteed not to overflow.
25256 */
25257 DUK_ASSERT(target_ustart + copy_size >= target_ustart); /* no overflow */
25258 DUK_ASSERT(target_ustart + copy_size >= copy_size); /* no overflow */
25259 copy_size = (duk_uint_t) target_length - target_ustart;
25260 }
25261
25262 DUK_DDD(DUK_DDDPRINT("making copy: target_ustart=%lu source_ustart=%lu copy_size=%lu",
25263 (unsigned long) target_ustart, (unsigned long) source_ustart,
25264 (unsigned long) copy_size));
25265
25266 DUK_ASSERT(copy_size >= 1);
25267 DUK_ASSERT(source_ustart <= (duk_uint_t) source_length);
25268 DUK_ASSERT(source_ustart + copy_size <= (duk_uint_t) source_length);
25269 DUK_ASSERT(target_ustart <= (duk_uint_t) target_length);
25270 DUK_ASSERT(target_ustart + copy_size <= (duk_uint_t) target_length);
25271
25272 /* Ensure copy is covered by underlying buffers. */
25273 DUK_ASSERT(h_bufarg->buf != NULL); /* length check */
25274 DUK_ASSERT(h_this->buf != NULL); /* length check */
25275 if (DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufarg, target_ustart + copy_size) &&
25276 DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, source_ustart + copy_size)) {
25277 /* Must use memmove() because copy area may overlap (source and target
25278 * buffer may be the same, or from different slices.
25279 */
25280 DUK_MEMMOVE((void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg) + target_ustart),
25281 (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + source_ustart),
25282 (size_t) copy_size);
25283 } else {
25284 DUK_DDD(DUK_DDDPRINT("buffer copy not covered by underlying buffer(s), ignoring"));
25285 }
25286
25287 silent_ignore:
25288 /* Return value is like write(), number of bytes written.
25289 * The return value matters because of code like:
25290 * "off += buf.copy(...)".
25291 */
25292 duk_push_uint(ctx, copy_size);
25293 return 1;
25294
25295 fail_bounds:
25296 DUK_DCERROR_RANGE_INVALID_ARGS(thr);
25297}
25298#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
25299
25300/*
25301 * TypedArray.prototype.set()
25302 *
25303 * TypedArray set() is pretty interesting to implement because:
25304 *
25305 * - The source argument may be a plain array or a typedarray. If the
25306 * source is a TypedArray, values are decoded and re-encoded into the
25307 * target (not as a plain byte copy). This may happen even when the
25308 * element byte size is the same, e.g. integer values may be re-encoded
25309 * into floats.
25310 *
25311 * - Source and target may refer to the same underlying buffer, so that
25312 * the set() operation may overlap. The specification requires that this
25313 * must work as if a copy was made before the operation. Note that this
25314 * is NOT a simple memmove() situation because the source and target
25315 * byte sizes may be different -- e.g. a 4-byte source (Int8Array) may
25316 * expand to a 16-byte target (Uint32Array) so that the target overlaps
25317 * the source both from beginning and the end (unlike in typical memmove).
25318 *
25319 * - Even if 'buf' pointers of the source and target differ, there's no
25320 * guarantee that their memory areas don't overlap. This may be the
25321 * case with external buffers.
25322 *
25323 * Even so, it is nice to optimize for the common case:
25324 *
25325 * - Source and target separate buffers or non-overlapping.
25326 *
25327 * - Source and target have a compatible type so that a plain byte copy
25328 * is possible. Note that while e.g. uint8 and int8 are compatible
25329 * (coercion one way or another doesn't change the byte representation),
25330 * e.g. int8 and uint8clamped are NOT compatible when writing int8
25331 * values into uint8clamped typedarray (-1 would clamp to 0 for instance).
25332 *
25333 * See test-bi-typedarray-proto-set.js.
25334 */
25335
25336#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
25337DUK_INTERNAL duk_ret_t duk_bi_typedarray_set(duk_context *ctx) {
25338 duk_hthread *thr;
25339 duk_hbufobj *h_this;
25340 duk_hobject *h_obj;
25341 duk_uarridx_t i, n;
25342 duk_int_t offset_signed;
25343 duk_uint_t offset_elems;
25344 duk_uint_t offset_bytes;
25345
25346 thr = (duk_hthread *) ctx;
25347 DUK_UNREF(thr);
25348
25349 h_this = duk__require_bufobj_this(ctx);
25350 DUK_ASSERT(h_this != NULL);
25351 DUK_ASSERT_HBUFOBJ_VALID(h_this);
25352
25353 if (h_this->buf == NULL) {
25354 DUK_DDD(DUK_DDDPRINT("source neutered, skip copy"));
25355 return 0;
25356 }
25357
25358 duk_hbufobj_promote_plain(ctx, 0);
25359 h_obj = duk_known_hobject(ctx, 0);
25360
25361 /* XXX: V8 throws a TypeError for negative values. Would it
25362 * be more useful to interpret negative offsets here from the
25363 * end of the buffer too?
25364 */
25365 offset_signed = duk_to_int(ctx, 1);
25366 if (offset_signed < 0) {
25367 /* For some reason this is a TypeError (at least in V8). */
25368 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
25369 }
25370 offset_elems = (duk_uint_t) offset_signed;
25371 offset_bytes = offset_elems << h_this->shift;
25372 if ((offset_bytes >> h_this->shift) != offset_elems) {
25373 /* Byte length would overflow. */
25374 /* XXX: easier check with less code? */
25375 goto fail_args;
25376 }
25377 if (offset_bytes > h_this->length) {
25378 /* Equality may be OK but >length not. Checking
25379 * this explicitly avoids some overflow cases
25380 * below.
25381 */
25382 goto fail_args;
25383 }
25384 DUK_ASSERT(offset_bytes <= h_this->length);
25385
25386 /* Fast path: source is a TypedArray (or any bufobj). */
25387
25388 if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
25389 duk_hbufobj *h_bufarg;
25390#if !defined(DUK_USE_PREFER_SIZE)
25391 duk_uint16_t comp_mask;
25392#endif
25393 duk_small_int_t no_overlap = 0;
25394 duk_uint_t src_length;
25395 duk_uint_t dst_length;
25396 duk_uint_t dst_length_elems;
25397 duk_uint8_t *p_src_base;
25398 duk_uint8_t *p_src_end;
25399 duk_uint8_t *p_src;
25400 duk_uint8_t *p_dst_base;
25401 duk_uint8_t *p_dst;
25402 duk_small_uint_t src_elem_size;
25403 duk_small_uint_t dst_elem_size;
25404
25405 h_bufarg = (duk_hbufobj *) h_obj;
25406 DUK_ASSERT_HBUFOBJ_VALID(h_bufarg);
25407
25408 if (h_bufarg->buf == NULL) {
25409 DUK_DDD(DUK_DDDPRINT("target neutered, skip copy"));
25410 return 0;
25411 }
25412
25413 /* Nominal size check. */
25414 src_length = h_bufarg->length; /* bytes in source */
25415 dst_length_elems = (src_length >> h_bufarg->shift); /* elems in source and dest */
25416 dst_length = dst_length_elems << h_this->shift; /* bytes in dest */
25417 if ((dst_length >> h_this->shift) != dst_length_elems) {
25418 /* Byte length would overflow. */
25419 /* XXX: easier check with less code? */
25420 goto fail_args;
25421 }
25422 DUK_DDD(DUK_DDDPRINT("nominal size check: src_length=%ld, dst_length=%ld",
25423 (long) src_length, (long) dst_length));
25424 DUK_ASSERT(offset_bytes <= h_this->length);
25425 if (dst_length > h_this->length - offset_bytes) {
25426 /* Overflow not an issue because subtraction is used on the right
25427 * side and guaranteed to be >= 0.
25428 */
25429 DUK_DDD(DUK_DDDPRINT("copy exceeds target buffer nominal length"));
25430 goto fail_args;
25431 }
25432 if (!DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_this, offset_bytes + dst_length)) {
25433 DUK_DDD(DUK_DDDPRINT("copy not covered by underlying target buffer, ignore"));
25434 return 0;
25435 }
25436
25437 p_src_base = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufarg);
25438 p_dst_base = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + offset_bytes;
25439
25440 /* Check actual underlying buffers for validity and that they
25441 * cover the copy. No side effects are allowed after the check
25442 * so that the validity status doesn't change.
25443 */
25444 if (!DUK_HBUFOBJ_VALID_SLICE(h_this) ||
25445 !DUK_HBUFOBJ_VALID_SLICE(h_bufarg)) {
25446 /* The condition could be more narrow and check for the
25447 * copy area only, but there's no need for fine grained
25448 * behavior when the underlying buffer is misconfigured.
25449 */
25450 DUK_DDD(DUK_DDDPRINT("source and/or target not covered by underlying buffer, skip copy"));
25451 return 0;
25452 }
25453
25454 /* We want to do a straight memory copy if possible: this is
25455 * an important operation because .set() is the TypedArray
25456 * way to copy chunks of memory. However, because set()
25457 * conceptually works in terms of elements, not all views are
25458 * compatible with direct byte copying.
25459 *
25460 * If we do manage a direct copy, the "overlap issue" handled
25461 * below can just be solved using memmove() because the source
25462 * and destination element sizes are necessarily equal.
25463 */
25464
25465#if !defined(DUK_USE_PREFER_SIZE)
25466 DUK_ASSERT(h_this->elem_type < sizeof(duk__buffer_elemtype_copy_compatible) / sizeof(duk_uint16_t));
25467 comp_mask = duk__buffer_elemtype_copy_compatible[h_this->elem_type];
25468 if (comp_mask & (1 << h_bufarg->elem_type)) {
25469 DUK_ASSERT(src_length == dst_length);
25470
25471 DUK_DDD(DUK_DDDPRINT("fast path: able to use memmove() because views are compatible"));
25472 DUK_MEMMOVE((void *) p_dst_base, (const void *) p_src_base, (size_t) dst_length);
25473 return 0;
25474 }
25475 DUK_DDD(DUK_DDDPRINT("fast path: views are not compatible with a byte copy, copy by item"));
25476#endif /* !DUK_USE_PREFER_SIZE */
25477
25478 /* We want to avoid making a copy to process set() but that's
25479 * not always possible: the source and the target may overlap
25480 * and because element sizes are different, the overlap cannot
25481 * always be handled with a memmove() or choosing the copy
25482 * direction in a certain way. For example, if source type is
25483 * uint8 and target type is uint32, the target area may exceed
25484 * the source area from both ends!
25485 *
25486 * Note that because external buffers may point to the same
25487 * memory areas, we must ultimately make this check using
25488 * pointers.
25489 *
25490 * NOTE: careful with side effects: any side effect may cause
25491 * a buffer resize (or external buffer pointer/length update)!
25492 */
25493
25494 DUK_DDD(DUK_DDDPRINT("overlap check: p_src_base=%p, src_length=%ld, "
25495 "p_dst_base=%p, dst_length=%ld",
25496 (void *) p_src_base, (long) src_length,
25497 (void *) p_dst_base, (long) dst_length));
25498
25499 if (p_src_base >= p_dst_base + dst_length || /* source starts after dest ends */
25500 p_src_base + src_length <= p_dst_base) { /* source ends before dest starts */
25501 no_overlap = 1;
25502 }
25503
25504 if (!no_overlap) {
25505 /* There's overlap: the desired end result is that
25506 * conceptually a copy is made to avoid "trampling"
25507 * of source data by destination writes. We make
25508 * an actual temporary copy to handle this case.
25509 */
25510 duk_uint8_t *p_src_copy;
25511
25512 DUK_DDD(DUK_DDDPRINT("there is overlap, make a copy of the source"));
25513 p_src_copy = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, src_length);
25514 DUK_ASSERT(p_src_copy != NULL);
25515 DUK_MEMCPY((void *) p_src_copy, (const void *) p_src_base, (size_t) src_length);
25516
25517 p_src_base = p_src_copy; /* use p_src_base from now on */
25518 }
25519 /* Value stack intentionally mixed size here. */
25520
25521 DUK_DDD(DUK_DDDPRINT("after overlap check: p_src_base=%p, src_length=%ld, "
25522 "p_dst_base=%p, dst_length=%ld, valstack top=%ld",
25523 (void *) p_src_base, (long) src_length,
25524 (void *) p_dst_base, (long) dst_length,
25525 (long) duk_get_top(ctx)));
25526
25527 /* Ready to make the copy. We must proceed element by element
25528 * and must avoid any side effects that might cause the buffer
25529 * validity check above to become invalid.
25530 *
25531 * Although we work through the value stack here, only plain
25532 * numbers are handled which should be side effect safe.
25533 */
25534
25535 src_elem_size = 1 << h_bufarg->shift;
25536 dst_elem_size = 1 << h_this->shift;
25537 p_src = p_src_base;
25538 p_dst = p_dst_base;
25539 p_src_end = p_src_base + src_length;
25540
25541 while (p_src != p_src_end) {
25542 DUK_DDD(DUK_DDDPRINT("fast path per element copy loop: "
25543 "p_src=%p, p_src_end=%p, p_dst=%p",
25544 (void *) p_src, (void *) p_src_end, (void *) p_dst));
25545 /* A validated read() is always a number, so it's write coercion
25546 * is always side effect free an won't invalidate pointers etc.
25547 */
25548 duk_hbufobj_push_validated_read(ctx, h_bufarg, p_src, src_elem_size);
25549 duk_hbufobj_validated_write(ctx, h_this, p_dst, dst_elem_size);
25550 duk_pop(ctx);
25551 p_src += src_elem_size;
25552 p_dst += dst_elem_size;
25553 }
25554
25555 return 0;
25556 } else {
25557 /* Slow path: quite slow, but we save space by using the property code
25558 * to write coerce target values. We don't need to worry about overlap
25559 * here because the source is not a TypedArray.
25560 *
25561 * We could use the bufobj write coercion helper but since the
25562 * property read may have arbitrary side effects, full validity checks
25563 * would be needed for every element anyway.
25564 */
25565
25566 n = (duk_uarridx_t) duk_get_length(ctx, 0);
25567 DUK_ASSERT(offset_bytes <= h_this->length);
25568 if ((n << h_this->shift) > h_this->length - offset_bytes) {
25569 /* Overflow not an issue because subtraction is used on the right
25570 * side and guaranteed to be >= 0.
25571 */
25572 DUK_DDD(DUK_DDDPRINT("copy exceeds target buffer nominal length"));
25573 goto fail_args;
25574 }
25575
25576 /* There's no need to check for buffer validity status for the
25577 * target here: the property access code will do that for each
25578 * element. Moreover, if we did check the validity here, side
25579 * effects from reading the source argument might invalidate
25580 * the results anyway.
25581 */
25582
25583 DUK_ASSERT_TOP(ctx, 2);
25584 duk_push_this(ctx);
25585
25586 for (i = 0; i < n; i++) {
25587 duk_get_prop_index(ctx, 0, i);
25588 duk_put_prop_index(ctx, 2, offset_elems + i);
25589 }
25590 }
25591
25592 return 0;
25593
25594 fail_args:
25595 DUK_DCERROR_RANGE_INVALID_ARGS(thr);
25596}
25597#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
25598
25599/*
25600 * Node.js Buffer.prototype.slice([start], [end])
25601 * ArrayBuffer.prototype.slice(begin, [end])
25602 * TypedArray.prototype.subarray(begin, [end])
25603 *
25604 * The API calls are almost identical; negative indices are counted from end
25605 * of buffer, and final indices are clamped (allowing crossed indices). Main
25606 * differences:
25607 *
25608 * - Copy/view behavior; Node.js .slice() and TypedArray .subarray() create
25609 * views, ArrayBuffer .slice() creates a copy
25610 *
25611 * - Resulting object has a different class and prototype depending on the
25612 * call (or 'this' argument)
25613 *
25614 * - TypedArray .subarray() arguments are element indices, not byte offsets
25615 *
25616 * - Plain buffer argument creates a plain buffer slice
25617 */
25618
25619#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
25620DUK_LOCAL void duk__arraybuffer_plain_slice(duk_context *ctx, duk_hbuffer *h_val) {
25621 duk_hthread *thr;
25622 duk_int_t start_offset, end_offset;
25623 duk_uint_t slice_length;
25624 duk_uint8_t *p_copy;
25625 duk_size_t copy_length;
25626
25627 thr = (duk_hthread *) ctx;
25628 DUK_UNREF(thr);
25629
25630 duk__clamp_startend_negidx_shifted(ctx,
25631 (duk_int_t) DUK_HBUFFER_GET_SIZE(h_val),
25632 0 /*buffer_shift*/,
25633 0 /*idx_start*/,
25634 1 /*idx_end*/,
25635 &start_offset,
25636 &end_offset);
25637 DUK_ASSERT(end_offset <= (duk_int_t) DUK_HBUFFER_GET_SIZE(h_val));
25638 DUK_ASSERT(start_offset >= 0);
25639 DUK_ASSERT(end_offset >= start_offset);
25640 slice_length = (duk_uint_t) (end_offset - start_offset);
25641
25642 p_copy = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, (duk_size_t) slice_length);
25643 DUK_ASSERT(p_copy != NULL);
25644 copy_length = slice_length;
25645
25646 DUK_MEMCPY((void *) p_copy,
25647 (const void *) ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_val) + start_offset),
25648 copy_length);
25649}
25650#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
25651
25652#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
25653/* Shared helper for slice/subarray operation.
25654 * Magic: 0x01=isView, 0x02=copy, 0x04=Node.js Buffer special handling.
25655 */
25656DUK_INTERNAL duk_ret_t duk_bi_buffer_slice_shared(duk_context *ctx) {
25657 duk_hthread *thr;
25658 duk_small_int_t magic;
25659 duk_small_uint_t res_class_num;
25660 duk_small_int_t res_proto_bidx;
25661 duk_hbufobj *h_this;
25662 duk_hbufobj *h_bufobj;
25663 duk_hbuffer *h_val;
25664 duk_int_t start_offset, end_offset;
25665 duk_uint_t slice_length;
25666 duk_tval *tv;
25667
25668 thr = (duk_hthread *) ctx;
25669 DUK_UNREF(thr);
25670
25671 /* [ start end ] */
25672
25673 magic = duk_get_current_magic(ctx);
25674
25675 tv = duk_get_borrowed_this_tval(ctx);
25676 DUK_ASSERT(tv != NULL);
25677
25678 if (DUK_TVAL_IS_BUFFER(tv)) {
25679 /* For plain buffers return a plain buffer slice. */
25680 h_val = DUK_TVAL_GET_BUFFER(tv);
25681 DUK_ASSERT(h_val != NULL);
25682
25683 if (magic & 0x02) {
25684 /* Make copy: ArrayBuffer.prototype.slice() uses this. */
25685 duk__arraybuffer_plain_slice(ctx, h_val);
25686 return 1;
25687 } else {
25688 /* View into existing buffer: cannot be done if the
25689 * result is a plain buffer because there's no slice
25690 * info. So return an ArrayBuffer instance; coerce
25691 * the 'this' binding into an object and behave as if
25692 * the original call was for an Object-coerced plain
25693 * buffer (handled automatically by duk__require_bufobj_this()).
25694 */
25695
25696 DUK_DDD(DUK_DDDPRINT("slice() doesn't handle view into plain buffer, coerce 'this' to ArrayBuffer object"));
25697 /* fall through */
25698 }
25699 }
25700 tv = NULL; /* No longer valid nor needed. */
25701
25702 h_this = duk__require_bufobj_this(ctx);
25703
25704 /* Slice offsets are element (not byte) offsets, which only matters
25705 * for TypedArray views, Node.js Buffer and ArrayBuffer have shift
25706 * zero so byte and element offsets are the same. Negative indices
25707 * are counted from end of slice, crossed indices are allowed (and
25708 * result in zero length result), and final values are clamped
25709 * against the current slice. There's intentionally no check
25710 * against the underlying buffer here.
25711 */
25712
25713 duk__clamp_startend_negidx_shifted(ctx,
25714 (duk_int_t) h_this->length,
25715 (duk_uint8_t) h_this->shift,
25716 0 /*idx_start*/,
25717 1 /*idx_end*/,
25718 &start_offset,
25719 &end_offset);
25720 DUK_ASSERT(end_offset >= start_offset);
25721 slice_length = (duk_uint_t) (end_offset - start_offset);
25722
25723 /* The resulting buffer object gets the same class and prototype as
25724 * the buffer in 'this', e.g. if the input is a Uint8Array the
25725 * result is a Uint8Array; if the input is a Float32Array, the
25726 * result is a Float32Array. The result internal prototype should
25727 * be the default prototype for the class (e.g. initial value of
25728 * Uint8Array.prototype), not copied from the argument (Duktape 1.x
25729 * did that).
25730 *
25731 * Node.js Buffers have special handling: they're Uint8Arrays as far
25732 * as the internal class is concerned, so the new Buffer should also
25733 * be an Uint8Array but inherit from Buffer.prototype.
25734 */
25735 res_class_num = DUK_HOBJECT_GET_CLASS_NUMBER((duk_hobject *) h_this);
25736 DUK_ASSERT(res_class_num >= DUK_HOBJECT_CLASS_BUFOBJ_MIN); /* type check guarantees */
25737 DUK_ASSERT(res_class_num <= DUK_HOBJECT_CLASS_BUFOBJ_MAX);
25738 res_proto_bidx = duk__buffer_proto_from_classnum[res_class_num - DUK_HOBJECT_CLASS_BUFOBJ_MIN];
25739 if (magic & 0x04) {
25740 res_proto_bidx = DUK_BIDX_NODEJS_BUFFER_PROTOTYPE;
25741 }
25742 h_bufobj = duk_push_bufobj_raw(ctx,
25743 DUK_HOBJECT_FLAG_EXTENSIBLE |
25744 DUK_HOBJECT_FLAG_BUFOBJ |
25745 DUK_HOBJECT_CLASS_AS_FLAGS(res_class_num),
25746 res_proto_bidx);
25747 DUK_ASSERT(h_bufobj != NULL);
25748
25749 h_bufobj->length = slice_length;
25750 h_bufobj->shift = h_this->shift; /* inherit */
25751 h_bufobj->elem_type = h_this->elem_type; /* inherit */
25752 h_bufobj->is_typedarray = magic & 0x01;
25753 DUK_ASSERT(h_bufobj->is_typedarray == 0 || h_bufobj->is_typedarray == 1);
25754
25755 h_val = h_this->buf;
25756 if (h_val == NULL) {
25757 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
25758 }
25759
25760 if (magic & 0x02) {
25761 /* non-zero: make copy */
25762 duk_uint8_t *p_copy;
25763 duk_size_t copy_length;
25764
25765 p_copy = (duk_uint8_t *) duk_push_fixed_buffer_zero(ctx, (duk_size_t) slice_length); /* must be zeroed, not all bytes always copied */
25766 DUK_ASSERT(p_copy != NULL);
25767
25768 /* Copy slice, respecting underlying buffer limits; remainder
25769 * is left as zero.
25770 */
25771 copy_length = DUK_HBUFOBJ_CLAMP_BYTELENGTH(h_this, slice_length);
25772 DUK_MEMCPY((void *) p_copy,
25773 (const void *) (DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this) + start_offset),
25774 copy_length);
25775
25776 h_val = duk_known_hbuffer(ctx, -1);
25777
25778 h_bufobj->buf = h_val;
25779 DUK_HBUFFER_INCREF(thr, h_val);
25780 DUK_ASSERT(h_bufobj->offset == 0);
25781
25782 duk_pop(ctx); /* reachable so pop OK */
25783 } else {
25784 h_bufobj->buf = h_val;
25785 DUK_HBUFFER_INCREF(thr, h_val);
25786 h_bufobj->offset = (duk_uint_t) (h_this->offset + start_offset);
25787
25788 /* Copy the .buffer property, needed for TypedArray.prototype.subarray().
25789 *
25790 * XXX: limit copy only for TypedArray classes specifically?
25791 */
25792
25793 DUK_ASSERT(h_bufobj->buf_prop == NULL);
25794 h_bufobj->buf_prop = h_this->buf_prop; /* may be NULL */
25795 DUK_HOBJECT_INCREF_ALLOWNULL(thr, (duk_hobject *) h_bufobj->buf_prop);
25796 }
25797 /* unbalanced stack on purpose */
25798
25799 DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
25800 return 1;
25801}
25802#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
25803
25804/*
25805 * Node.js Buffer.isEncoding()
25806 */
25807
25808#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
25809DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_encoding(duk_context *ctx) {
25810 const char *encoding;
25811
25812 /* only accept lowercase 'utf8' now. */
25813
25814 encoding = duk_to_string(ctx, 0);
25815 DUK_ASSERT(duk_is_string(ctx, 0)); /* guaranteed by duk_to_string() */
25816 duk_push_boolean(ctx, DUK_STRCMP(encoding, "utf8") == 0);
25817 return 1;
25818}
25819#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
25820
25821/*
25822 * Node.js Buffer.isBuffer()
25823 */
25824
25825#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
25826DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_is_buffer(duk_context *ctx) {
25827 duk_hthread *thr;
25828 duk_hobject *h;
25829 duk_hobject *h_proto;
25830 duk_bool_t ret = 0;
25831
25832 thr = (duk_hthread *) ctx;
25833
25834 DUK_ASSERT(duk_get_top(ctx) >= 1); /* nargs */
25835 h = duk_get_hobject(ctx, 0);
25836 if (h != NULL) {
25837 h_proto = thr->builtins[DUK_BIDX_NODEJS_BUFFER_PROTOTYPE];
25838 DUK_ASSERT(h_proto != NULL);
25839
25840 h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
25841 if (h != NULL) {
25842 ret = duk_hobject_prototype_chain_contains(thr, h, h_proto, 0 /*ignore_loop*/);
25843 }
25844 }
25845
25846 duk_push_boolean(ctx, ret);
25847 return 1;
25848}
25849#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
25850
25851/*
25852 * Node.js Buffer.byteLength()
25853 */
25854
25855#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
25856DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_byte_length(duk_context *ctx) {
25857 const char *str;
25858 duk_size_t len;
25859
25860 /* At the moment Buffer(<str>) will just use the string bytes as
25861 * is (ignoring encoding), so we return the string length here
25862 * unconditionally.
25863 */
25864
25865 /* XXX: to be revised; Old Node.js behavior just coerces any buffer
25866 * values to string:
25867 * $ node
25868 * > Buffer.byteLength(new Uint32Array(10))
25869 * 20
25870 * > Buffer.byteLength(new Uint32Array(100))
25871 * 20
25872 * (The 20 comes from '[object Uint32Array]'.length
25873 */
25874
25875 str = duk_to_lstring(ctx, 0, &len);
25876 DUK_UNREF(str);
25877 duk_push_size_t(ctx, len);
25878 return 1;
25879}
25880#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
25881
25882/*
25883 * Node.js Buffer.concat()
25884 */
25885
25886#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
25887DUK_INTERNAL duk_ret_t duk_bi_nodejs_buffer_concat(duk_context *ctx) {
25888 duk_hthread *thr;
25889 duk_hobject *h_arg;
25890 duk_int_t total_length = 0;
25891 duk_hbufobj *h_bufobj;
25892 duk_hbufobj *h_bufres;
25893 duk_hbuffer *h_val;
25894 duk_uint_t i, n;
25895 duk_uint8_t *p;
25896 duk_size_t space_left;
25897 duk_size_t copy_size;
25898
25899 thr = (duk_hthread *) ctx;
25900 DUK_UNREF(thr);
25901
25902 /* Node.js accepts only actual Arrays. */
25903 h_arg = duk_require_hobject(ctx, 0);
25904 if (DUK_HOBJECT_GET_CLASS_NUMBER(h_arg) != DUK_HOBJECT_CLASS_ARRAY) {
25905 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
25906 }
25907
25908 /* Compute result length and validate argument buffers. */
25909 n = (duk_uint_t) duk_get_length(ctx, 0);
25910 for (i = 0; i < n; i++) {
25911 /* Neutered checks not necessary here: neutered buffers have
25912 * zero 'length' so we'll effectively skip them.
25913 */
25914 DUK_ASSERT_TOP(ctx, 2); /* [ array totalLength ] */
25915 duk_get_prop_index(ctx, 0, (duk_uarridx_t) i); /* -> [ array totalLength buf ] */
25916 h_bufobj = duk__require_bufobj_value(ctx, 2);
25917 DUK_ASSERT(h_bufobj != NULL);
25918 total_length += h_bufobj->length;
25919 duk_pop(ctx);
25920 }
25921 /* In Node.js v0.12.1 a 1-element array is special and won't create a
25922 * copy, this was fixed later so an explicit check no longer needed.
25923 */
25924
25925 /* User totalLength overrides a computed length, but we'll check
25926 * every copy in the copy loop. Note that duk_to_uint() can
25927 * technically have arbitrary side effects so we need to recheck
25928 * the buffers in the copy loop.
25929 */
25930 if (!duk_is_undefined(ctx, 1) && n > 0) {
25931 /* For n == 0, Node.js ignores totalLength argument and
25932 * returns a zero length buffer.
25933 */
25934 total_length = duk_to_int(ctx, 1);
25935 }
25936 if (total_length < 0) {
25937 DUK_DCERROR_RANGE_INVALID_ARGS(thr);
25938 }
25939
25940 h_bufres = duk_push_bufobj_raw(ctx,
25941 DUK_HOBJECT_FLAG_EXTENSIBLE |
25942 DUK_HOBJECT_FLAG_BUFOBJ |
25943 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_UINT8ARRAY),
25944 DUK_BIDX_NODEJS_BUFFER_PROTOTYPE);
25945 DUK_ASSERT(h_bufres != NULL);
25946
25947 p = (duk_uint8_t *) duk_push_fixed_buffer_zero(ctx, total_length); /* must be zeroed, all bytes not necessarily written over */
25948 DUK_ASSERT(p != NULL);
25949 space_left = total_length;
25950
25951 for (i = 0; i < n; i++) {
25952 DUK_ASSERT_TOP(ctx, 4); /* [ array totalLength bufres buf ] */
25953
25954 duk_get_prop_index(ctx, 0, (duk_uarridx_t) i);
25955 h_bufobj = duk__require_bufobj_value(ctx, 4);
25956 DUK_ASSERT(h_bufobj != NULL);
25957
25958 copy_size = h_bufobj->length;
25959 if (copy_size > space_left) {
25960 copy_size = space_left;
25961 }
25962
25963 if (h_bufobj->buf != NULL &&
25964 DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) {
25965 DUK_MEMCPY((void *) p,
25966 (const void *) DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_bufobj),
25967 copy_size);
25968 } else {
25969 /* Just skip, leaving zeroes in the result. */
25970 ;
25971 }
25972 p += copy_size;
25973 space_left -= copy_size;
25974
25975 duk_pop(ctx);
25976 }
25977
25978 h_val = duk_known_hbuffer(ctx, -1);
25979
25980 duk__set_bufobj_buffer(ctx, h_bufres, h_val);
25981 h_bufres->is_typedarray = 1;
25982 DUK_ASSERT_HBUFOBJ_VALID(h_bufres);
25983
25984 duk_pop(ctx); /* pop plain buffer, now reachable through h_bufres */
25985
25986 return 1; /* return h_bufres */
25987}
25988#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
25989
25990/*
25991 * Shared readfield and writefield methods
25992 *
25993 * The readfield/writefield methods need support for endianness and field
25994 * types. All offsets are byte based so no offset shifting is needed.
25995 */
25996
25997#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
25998/* Format of magic, bits:
25999 * 0...1: field type; 0=uint8, 1=uint16, 2=uint32, 3=float, 4=double, 5=unused, 6=unused, 7=unused
26000 * 3: endianness: 0=little, 1=big
26001 * 4: signed: 1=yes, 0=no
26002 * 5: typedarray: 1=yes, 0=no
26003 */
26004#define DUK__FLD_8BIT 0
26005#define DUK__FLD_16BIT 1
26006#define DUK__FLD_32BIT 2
26007#define DUK__FLD_FLOAT 3
26008#define DUK__FLD_DOUBLE 4
26009#define DUK__FLD_VARINT 5
26010#define DUK__FLD_BIGENDIAN (1 << 3)
26011#define DUK__FLD_SIGNED (1 << 4)
26012#define DUK__FLD_TYPEDARRAY (1 << 5)
26013
26014/* XXX: split into separate functions for each field type? */
26015DUK_INTERNAL duk_ret_t duk_bi_buffer_readfield(duk_context *ctx) {
26016 duk_hthread *thr;
26017 duk_small_int_t magic = (duk_small_int_t) duk_get_current_magic(ctx);
26018 duk_small_int_t magic_ftype;
26019 duk_small_int_t magic_bigendian;
26020 duk_small_int_t magic_signed;
26021 duk_small_int_t magic_typedarray;
26022 duk_small_int_t endswap;
26023 duk_hbufobj *h_this;
26024 duk_bool_t no_assert;
26025 duk_int_t offset_signed;
26026 duk_uint_t offset;
26027 duk_uint_t buffer_length;
26028 duk_uint_t check_length;
26029 duk_uint8_t *buf;
26031
26032 thr = (duk_hthread *) ctx;
26033 DUK_UNREF(thr);
26034
26035 magic_ftype = magic & 0x0007;
26036 magic_bigendian = magic & 0x0008;
26037 magic_signed = magic & 0x0010;
26038 magic_typedarray = magic & 0x0020;
26039
26040 h_this = duk__require_bufobj_this(ctx); /* XXX: very inefficient for plain buffers */
26041 DUK_ASSERT(h_this != NULL);
26042 buffer_length = h_this->length;
26043
26044 /* [ offset noAssert ], when ftype != DUK__FLD_VARINT */
26045 /* [ offset fieldByteLength noAssert ], when ftype == DUK__FLD_VARINT */
26046 /* [ offset littleEndian ], when DUK__FLD_TYPEDARRAY (regardless of ftype) */
26047
26048 /* Handle TypedArray vs. Node.js Buffer arg differences */
26049 if (magic_typedarray) {
26050 no_assert = 0;
26051#if defined(DUK_USE_INTEGER_LE)
26052 endswap = !duk_to_boolean(ctx, 1); /* 1=little endian */
26053#else
26054 endswap = duk_to_boolean(ctx, 1); /* 1=little endian */
26055#endif
26056 } else {
26057 no_assert = duk_to_boolean(ctx, (magic_ftype == DUK__FLD_VARINT) ? 2 : 1);
26058#if defined(DUK_USE_INTEGER_LE)
26059 endswap = magic_bigendian;
26060#else
26061 endswap = !magic_bigendian;
26062#endif
26063 }
26064
26065 /* Offset is coerced first to signed integer range and then to unsigned.
26066 * This ensures we can add a small byte length (1-8) to the offset in
26067 * bound checks and not wrap.
26068 */
26069 offset_signed = duk_to_int(ctx, 0);
26070 offset = (duk_uint_t) offset_signed;
26071 if (offset_signed < 0) {
26072 goto fail_bounds;
26073 }
26074
26075 DUK_DDD(DUK_DDDPRINT("readfield, buffer_length=%ld, offset=%ld, no_assert=%d, "
26076 "magic=%04x, magic_fieldtype=%d, magic_bigendian=%d, magic_signed=%d, "
26077 "endswap=%d",
26078 (long) buffer_length, (long) offset, (int) no_assert,
26079 (unsigned int) magic, (int) magic_ftype, (int) (magic_bigendian >> 3),
26080 (int) (magic_signed >> 4), (int) endswap));
26081
26082 /* Update 'buffer_length' to be the effective, safe limit which
26083 * takes into account the underlying buffer. This value will be
26084 * potentially invalidated by any side effect.
26085 */
26086 check_length = DUK_HBUFOBJ_CLAMP_BYTELENGTH(h_this, buffer_length);
26087 DUK_DDD(DUK_DDDPRINT("buffer_length=%ld, check_length=%ld",
26088 (long) buffer_length, (long) check_length));
26089
26090 if (h_this->buf) {
26091 buf = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this);
26092 } else {
26093 /* Neutered. We could go into the switch-case safely with
26094 * buf == NULL because check_length == 0. To avoid scanbuild
26095 * warnings, fail directly instead.
26096 */
26097 DUK_ASSERT(check_length == 0);
26098 goto fail_neutered;
26099 }
26100 DUK_ASSERT(buf != NULL);
26101
26102 switch (magic_ftype) {
26103 case DUK__FLD_8BIT: {
26104 duk_uint8_t tmp;
26105 if (offset + 1U > check_length) {
26106 goto fail_bounds;
26107 }
26108 tmp = buf[offset];
26109 if (magic_signed) {
26110 duk_push_int(ctx, (duk_int_t) ((duk_int8_t) tmp));
26111 } else {
26112 duk_push_uint(ctx, (duk_uint_t) tmp);
26113 }
26114 break;
26115 }
26116 case DUK__FLD_16BIT: {
26117 duk_uint16_t tmp;
26118 if (offset + 2U > check_length) {
26119 goto fail_bounds;
26120 }
26121 DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 2);
26122 tmp = du.us[0];
26123 if (endswap) {
26124 tmp = DUK_BSWAP16(tmp);
26125 }
26126 if (magic_signed) {
26127 duk_push_int(ctx, (duk_int_t) ((duk_int16_t) tmp));
26128 } else {
26129 duk_push_uint(ctx, (duk_uint_t) tmp);
26130 }
26131 break;
26132 }
26133 case DUK__FLD_32BIT: {
26134 duk_uint32_t tmp;
26135 if (offset + 4U > check_length) {
26136 goto fail_bounds;
26137 }
26138 DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 4);
26139 tmp = du.ui[0];
26140 if (endswap) {
26141 tmp = DUK_BSWAP32(tmp);
26142 }
26143 if (magic_signed) {
26144 duk_push_int(ctx, (duk_int_t) ((duk_int32_t) tmp));
26145 } else {
26146 duk_push_uint(ctx, (duk_uint_t) tmp);
26147 }
26148 break;
26149 }
26150 case DUK__FLD_FLOAT: {
26151 duk_uint32_t tmp;
26152 if (offset + 4U > check_length) {
26153 goto fail_bounds;
26154 }
26155 DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 4);
26156 if (endswap) {
26157 tmp = du.ui[0];
26158 tmp = DUK_BSWAP32(tmp);
26159 du.ui[0] = tmp;
26160 }
26161 duk_push_number(ctx, (duk_double_t) du.f[0]);
26162 break;
26163 }
26164 case DUK__FLD_DOUBLE: {
26165 if (offset + 8U > check_length) {
26166 goto fail_bounds;
26167 }
26168 DUK_MEMCPY((void *) du.uc, (const void *) (buf + offset), 8);
26169 if (endswap) {
26170 DUK_DBLUNION_BSWAP64(&du);
26171 }
26172 duk_push_number(ctx, (duk_double_t) du.d);
26173 break;
26174 }
26175 case DUK__FLD_VARINT: {
26176 /* Node.js Buffer variable width integer field. We don't really
26177 * care about speed here, so aim for shortest algorithm.
26178 */
26179 duk_int_t field_bytelen;
26180 duk_int_t i, i_step, i_end;
26181#if defined(DUK_USE_64BIT_OPS)
26182 duk_int64_t tmp;
26183 duk_small_uint_t shift_tmp;
26184#else
26185 duk_double_t tmp;
26186 duk_small_int_t highbyte;
26187#endif
26188 const duk_uint8_t *p;
26189
26190 field_bytelen = duk_get_int(ctx, 1); /* avoid side effects! */
26191 if (field_bytelen < 1 || field_bytelen > 6) {
26192 goto fail_field_length;
26193 }
26194 if (offset + (duk_uint_t) field_bytelen > check_length) {
26195 goto fail_bounds;
26196 }
26197 p = (const duk_uint8_t *) (buf + offset);
26198
26199 /* Slow gathering of value using either 64-bit arithmetic
26200 * or IEEE doubles if 64-bit types not available. Handling
26201 * of negative numbers is a bit non-obvious in both cases.
26202 */
26203
26204 if (magic_bigendian) {
26205 /* Gather in big endian */
26206 i = 0;
26207 i_step = 1;
26208 i_end = field_bytelen; /* one i_step over */
26209 } else {
26210 /* Gather in little endian */
26211 i = field_bytelen - 1;
26212 i_step = -1;
26213 i_end = -1; /* one i_step over */
26214 }
26215
26216#if defined(DUK_USE_64BIT_OPS)
26217 tmp = 0;
26218 do {
26219 DUK_ASSERT(i >= 0 && i < field_bytelen);
26220 tmp = (tmp << 8) + (duk_int64_t) p[i];
26221 i += i_step;
26222 } while (i != i_end);
26223
26224 if (magic_signed) {
26225 /* Shift to sign extend. */
26226 shift_tmp = 64 - (field_bytelen * 8);
26227 tmp = (tmp << shift_tmp) >> shift_tmp;
26228 }
26229
26230 duk_push_i64(ctx, tmp);
26231#else
26232 highbyte = p[i];
26233 if (magic_signed && (highbyte & 0x80) != 0) {
26234 /* 0xff => 255 - 256 = -1; 0x80 => 128 - 256 = -128 */
26235 tmp = (duk_double_t) (highbyte - 256);
26236 } else {
26237 tmp = (duk_double_t) highbyte;
26238 }
26239 for (;;) {
26240 i += i_step;
26241 if (i == i_end) {
26242 break;
26243 }
26244 DUK_ASSERT(i >= 0 && i < field_bytelen);
26245 tmp = (tmp * 256.0) + (duk_double_t) p[i];
26246 }
26247
26248 duk_push_number(ctx, tmp);
26249#endif
26250 break;
26251 }
26252 default: { /* should never happen but default here */
26253 goto fail_bounds;
26254 }
26255 }
26256
26257 return 1;
26258
26259 fail_neutered:
26260 fail_field_length:
26261 fail_bounds:
26262 if (no_assert) {
26263 /* Node.js return value for noAssert out-of-bounds reads is
26264 * usually (but not always) NaN. Return NaN consistently.
26265 */
26266 duk_push_nan(ctx);
26267 return 1;
26268 }
26269 DUK_DCERROR_RANGE_INVALID_ARGS(thr);
26270}
26271#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
26272
26273#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
26274/* XXX: split into separate functions for each field type? */
26275DUK_INTERNAL duk_ret_t duk_bi_buffer_writefield(duk_context *ctx) {
26276 duk_hthread *thr;
26277 duk_small_int_t magic = (duk_small_int_t) duk_get_current_magic(ctx);
26278 duk_small_int_t magic_ftype;
26279 duk_small_int_t magic_bigendian;
26280 duk_small_int_t magic_signed;
26281 duk_small_int_t magic_typedarray;
26282 duk_small_int_t endswap;
26283 duk_hbufobj *h_this;
26284 duk_bool_t no_assert;
26285 duk_int_t offset_signed;
26286 duk_uint_t offset;
26287 duk_uint_t buffer_length;
26288 duk_uint_t check_length;
26289 duk_uint8_t *buf;
26291 duk_int_t nbytes = 0;
26292
26293 thr = (duk_hthread *) ctx;
26294 DUK_UNREF(thr);
26295
26296 magic_ftype = magic & 0x0007;
26297 magic_bigendian = magic & 0x0008;
26298 magic_signed = magic & 0x0010;
26299 magic_typedarray = magic & 0x0020;
26300 DUK_UNREF(magic_signed);
26301
26302 h_this = duk__require_bufobj_this(ctx); /* XXX: very inefficient for plain buffers */
26303 DUK_ASSERT(h_this != NULL);
26304 buffer_length = h_this->length;
26305
26306 /* [ value offset noAssert ], when ftype != DUK__FLD_VARINT */
26307 /* [ value offset fieldByteLength noAssert ], when ftype == DUK__FLD_VARINT */
26308 /* [ offset value littleEndian ], when DUK__FLD_TYPEDARRAY (regardless of ftype) */
26309
26310 /* Handle TypedArray vs. Node.js Buffer arg differences */
26311 if (magic_typedarray) {
26312 no_assert = 0;
26313#if defined(DUK_USE_INTEGER_LE)
26314 endswap = !duk_to_boolean(ctx, 2); /* 1=little endian */
26315#else
26316 endswap = duk_to_boolean(ctx, 2); /* 1=little endian */
26317#endif
26318 duk_swap(ctx, 0, 1); /* offset/value order different from Node.js */
26319 } else {
26320 no_assert = duk_to_boolean(ctx, (magic_ftype == DUK__FLD_VARINT) ? 3 : 2);
26321#if defined(DUK_USE_INTEGER_LE)
26322 endswap = magic_bigendian;
26323#else
26324 endswap = !magic_bigendian;
26325#endif
26326 }
26327
26328 /* Offset is coerced first to signed integer range and then to unsigned.
26329 * This ensures we can add a small byte length (1-8) to the offset in
26330 * bound checks and not wrap.
26331 */
26332 offset_signed = duk_to_int(ctx, 1);
26333 offset = (duk_uint_t) offset_signed;
26334
26335 /* We need 'nbytes' even for a failed offset; return value must be
26336 * (offset + nbytes) even when write fails due to invalid offset.
26337 */
26338 if (magic_ftype != DUK__FLD_VARINT) {
26339 DUK_ASSERT(magic_ftype >= 0 && magic_ftype < (duk_small_int_t) (sizeof(duk__buffer_nbytes_from_fldtype) / sizeof(duk_uint8_t)));
26340 nbytes = duk__buffer_nbytes_from_fldtype[magic_ftype];
26341 } else {
26342 nbytes = duk_get_int(ctx, 2);
26343 if (nbytes < 1 || nbytes > 6) {
26344 goto fail_field_length;
26345 }
26346 }
26347 DUK_ASSERT(nbytes >= 1 && nbytes <= 8);
26348
26349 /* Now we can check offset validity. */
26350 if (offset_signed < 0) {
26351 goto fail_bounds;
26352 }
26353
26354 DUK_DDD(DUK_DDDPRINT("writefield, value=%!T, buffer_length=%ld, offset=%ld, no_assert=%d, "
26355 "magic=%04x, magic_fieldtype=%d, magic_bigendian=%d, magic_signed=%d, "
26356 "endswap=%d",
26357 duk_get_tval(ctx, 0), (long) buffer_length, (long) offset, (int) no_assert,
26358 (unsigned int) magic, (int) magic_ftype, (int) (magic_bigendian >> 3),
26359 (int) (magic_signed >> 4), (int) endswap));
26360
26361 /* Coerce value to a number before computing check_length, so that
26362 * the field type specific coercion below can't have side effects
26363 * that would invalidate check_length.
26364 */
26365 duk_to_number(ctx, 0);
26366
26367 /* Update 'buffer_length' to be the effective, safe limit which
26368 * takes into account the underlying buffer. This value will be
26369 * potentially invalidated by any side effect.
26370 */
26371 check_length = DUK_HBUFOBJ_CLAMP_BYTELENGTH(h_this, buffer_length);
26372 DUK_DDD(DUK_DDDPRINT("buffer_length=%ld, check_length=%ld",
26373 (long) buffer_length, (long) check_length));
26374
26375 if (h_this->buf) {
26376 buf = DUK_HBUFOBJ_GET_SLICE_BASE(thr->heap, h_this);
26377 } else {
26378 /* Neutered. We could go into the switch-case safely with
26379 * buf == NULL because check_length == 0. To avoid scanbuild
26380 * warnings, fail directly instead.
26381 */
26382 DUK_ASSERT(check_length == 0);
26383 goto fail_neutered;
26384 }
26385 DUK_ASSERT(buf != NULL);
26386
26387 switch (magic_ftype) {
26388 case DUK__FLD_8BIT: {
26389 if (offset + 1U > check_length) {
26390 goto fail_bounds;
26391 }
26392 /* sign doesn't matter when writing */
26393 buf[offset] = (duk_uint8_t) duk_to_uint32(ctx, 0);
26394 break;
26395 }
26396 case DUK__FLD_16BIT: {
26397 duk_uint16_t tmp;
26398 if (offset + 2U > check_length) {
26399 goto fail_bounds;
26400 }
26401 tmp = (duk_uint16_t) duk_to_uint32(ctx, 0);
26402 if (endswap) {
26403 tmp = DUK_BSWAP16(tmp);
26404 }
26405 du.us[0] = tmp;
26406 /* sign doesn't matter when writing */
26407 DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 2);
26408 break;
26409 }
26410 case DUK__FLD_32BIT: {
26411 duk_uint32_t tmp;
26412 if (offset + 4U > check_length) {
26413 goto fail_bounds;
26414 }
26415 tmp = (duk_uint32_t) duk_to_uint32(ctx, 0);
26416 if (endswap) {
26417 tmp = DUK_BSWAP32(tmp);
26418 }
26419 du.ui[0] = tmp;
26420 /* sign doesn't matter when writing */
26421 DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 4);
26422 break;
26423 }
26424 case DUK__FLD_FLOAT: {
26425 duk_uint32_t tmp;
26426 if (offset + 4U > check_length) {
26427 goto fail_bounds;
26428 }
26429 du.f[0] = (duk_float_t) duk_to_number(ctx, 0);
26430 if (endswap) {
26431 tmp = du.ui[0];
26432 tmp = DUK_BSWAP32(tmp);
26433 du.ui[0] = tmp;
26434 }
26435 /* sign doesn't matter when writing */
26436 DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 4);
26437 break;
26438 }
26439 case DUK__FLD_DOUBLE: {
26440 if (offset + 8U > check_length) {
26441 goto fail_bounds;
26442 }
26443 du.d = (duk_double_t) duk_to_number(ctx, 0);
26444 if (endswap) {
26445 DUK_DBLUNION_BSWAP64(&du);
26446 }
26447 /* sign doesn't matter when writing */
26448 DUK_MEMCPY((void *) (buf + offset), (const void *) du.uc, 8);
26449 break;
26450 }
26451 case DUK__FLD_VARINT: {
26452 /* Node.js Buffer variable width integer field. We don't really
26453 * care about speed here, so aim for shortest algorithm.
26454 */
26455 duk_int_t field_bytelen;
26456 duk_int_t i, i_step, i_end;
26457#if defined(DUK_USE_64BIT_OPS)
26458 duk_int64_t tmp;
26459#else
26460 duk_double_t tmp;
26461#endif
26462 duk_uint8_t *p;
26463
26464 field_bytelen = (duk_int_t) nbytes;
26465 if (offset + (duk_uint_t) field_bytelen > check_length) {
26466 goto fail_bounds;
26467 }
26468
26469 /* Slow writing of value using either 64-bit arithmetic
26470 * or IEEE doubles if 64-bit types not available. There's
26471 * no special sign handling when writing varints.
26472 */
26473
26474 if (magic_bigendian) {
26475 /* Write in big endian */
26476 i = field_bytelen; /* one i_step added at top of loop */
26477 i_step = -1;
26478 i_end = 0;
26479 } else {
26480 /* Write in little endian */
26481 i = -1; /* one i_step added at top of loop */
26482 i_step = 1;
26483 i_end = field_bytelen - 1;
26484 }
26485
26486 /* XXX: The duk_to_number() cast followed by integer coercion
26487 * is platform specific so NaN, +/- Infinity, and out-of-bounds
26488 * values result in platform specific output now.
26489 * See: test-bi-nodejs-buffer-proto-varint-special.js
26490 */
26491
26492#if defined(DUK_USE_64BIT_OPS)
26493 tmp = (duk_int64_t) duk_to_number(ctx, 0);
26494 p = (duk_uint8_t *) (buf + offset);
26495 do {
26496 i += i_step;
26497 DUK_ASSERT(i >= 0 && i < field_bytelen);
26498 p[i] = (duk_uint8_t) (tmp & 0xff);
26499 tmp = tmp >> 8; /* unnecessary shift for last byte */
26500 } while (i != i_end);
26501#else
26502 tmp = duk_to_number(ctx, 0);
26503 p = (duk_uint8_t *) (buf + offset);
26504 do {
26505 i += i_step;
26506 tmp = DUK_FLOOR(tmp);
26507 DUK_ASSERT(i >= 0 && i < field_bytelen);
26508 p[i] = (duk_uint8_t) (DUK_FMOD(tmp, 256.0));
26509 tmp = tmp / 256.0; /* unnecessary div for last byte */
26510 } while (i != i_end);
26511#endif
26512 break;
26513 }
26514 default: { /* should never happen but default here */
26515 goto fail_bounds;
26516 }
26517 }
26518
26519 /* Node.js Buffer: return offset + #bytes written (i.e. next
26520 * write offset).
26521 */
26522 if (magic_typedarray) {
26523 /* For TypedArrays 'undefined' return value is specified
26524 * by ES2015 (matches V8).
26525 */
26526 return 0;
26527 }
26528 duk_push_uint(ctx, offset + nbytes);
26529 return 1;
26530
26531 fail_neutered:
26532 fail_field_length:
26533 fail_bounds:
26534 if (no_assert) {
26535 /* Node.js return value for failed writes is offset + #bytes
26536 * that would have been written.
26537 */
26538 /* XXX: for negative input offsets, 'offset' will be a large
26539 * positive value so the result here is confusing.
26540 */
26541 if (magic_typedarray) {
26542 return 0;
26543 }
26544 duk_push_uint(ctx, offset + nbytes);
26545 return 1;
26546 }
26547 DUK_DCERROR_RANGE_INVALID_ARGS(thr);
26548}
26549#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
26550
26551/*
26552 * Accessors for .buffer, .byteLength, .byteOffset
26553 */
26554
26555#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
26556DUK_INTERNAL duk_ret_t duk_bi_typedarray_buffer_getter(duk_context *ctx) {
26557 duk_hbufobj *h_bufobj;
26558
26559 h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(ctx, DUK__BUFOBJ_FLAG_THROW /*flags*/);
26560 DUK_ASSERT(h_bufobj != NULL);
26561 if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) {
26562 duk_hbufobj *h_res;
26563 duk_hbuffer *h_buf;
26564
26565 h_buf = (duk_hbuffer *) h_bufobj;
26566 h_res = duk_push_bufobj_raw(ctx,
26567 DUK_HOBJECT_FLAG_EXTENSIBLE |
26568 DUK_HOBJECT_FLAG_BUFOBJ |
26569 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARRAYBUFFER),
26570 DUK_BIDX_ARRAYBUFFER_PROTOTYPE);
26571 DUK_ASSERT(h_res != NULL);
26572 DUK_UNREF(h_res);
26573
26574 duk__set_bufobj_buffer(ctx, h_res, h_buf);
26575 DUK_ASSERT_HBUFOBJ_VALID(h_res);
26576
26577 DUK_DD(DUK_DDPRINT("autospawned .buffer ArrayBuffer: %!iT", duk_get_tval(ctx, -1)));
26578 return 1;
26579 } else {
26580 if (h_bufobj->buf_prop) {
26581 duk_push_hobject(ctx, h_bufobj->buf_prop);
26582 return 1;
26583 }
26584 }
26585 return 0;
26586}
26587
26588DUK_INTERNAL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_context *ctx) {
26589 duk_hbufobj *h_bufobj;
26590
26591 h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(ctx, DUK__BUFOBJ_FLAG_THROW /*flags*/);
26592 DUK_ASSERT(h_bufobj != NULL);
26593 if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) {
26594 duk_push_uint(ctx, 0);
26595 } else {
26596 /* If neutered must return 0; offset is zeroed during
26597 * neutering.
26598 */
26599 duk_push_uint(ctx, h_bufobj->offset);
26600 }
26601 return 1;
26602}
26603
26604DUK_INTERNAL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_context *ctx) {
26605 duk_hbufobj *h_bufobj;
26606
26607 h_bufobj = (duk_hbufobj *) duk__getrequire_bufobj_this(ctx, DUK__BUFOBJ_FLAG_THROW /*flags*/);
26608 DUK_ASSERT(h_bufobj != NULL);
26609 if (DUK_HEAPHDR_IS_BUFFER((duk_heaphdr *) h_bufobj)) {
26610 duk_hbuffer *h_buf;
26611
26612 h_buf = (duk_hbuffer *) h_bufobj;
26613 DUK_ASSERT(DUK_HBUFFER_GET_SIZE(h_buf) <= DUK_UINT_MAX); /* Buffer limits. */
26614 duk_push_uint(ctx, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_buf));
26615 } else {
26616 /* If neutered must return 0; length is zeroed during
26617 * neutering.
26618 */
26619 duk_push_uint(ctx, h_bufobj->length);
26620 }
26621 return 1;
26622}
26623#else /* DUK_USE_BUFFEROBJECT_SUPPORT */
26624/* No .buffer getter without ArrayBuffer support. */
26625#if 0
26626DUK_INTERNAL duk_ret_t duk_bi_typedarray_buffer_getter(duk_context *ctx) {
26627 return 0;
26628}
26629#endif
26630
26631DUK_INTERNAL duk_ret_t duk_bi_typedarray_byteoffset_getter(duk_context *ctx) {
26632 duk_push_uint(ctx, 0);
26633 return 1;
26634}
26635
26636DUK_INTERNAL duk_ret_t duk_bi_typedarray_bytelength_getter(duk_context *ctx) {
26637 duk_hbuffer *h_buf;
26638
26639 /* XXX: helper? */
26640 duk_push_this(ctx);
26641 h_buf = duk_require_hbuffer(ctx, -1);
26642 duk_push_uint(ctx, DUK_HBUFFER_GET_SIZE(h_buf));
26643 return 1;
26644}
26645#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
26646
26647/* automatic undefs */
26648#undef DUK__BUFOBJ_FLAG_PROMOTE
26649#undef DUK__BUFOBJ_FLAG_THROW
26650#undef DUK__FLD_16BIT
26651#undef DUK__FLD_32BIT
26652#undef DUK__FLD_8BIT
26653#undef DUK__FLD_BIGENDIAN
26654#undef DUK__FLD_DOUBLE
26655#undef DUK__FLD_FLOAT
26656#undef DUK__FLD_SIGNED
26657#undef DUK__FLD_TYPEDARRAY
26658#undef DUK__FLD_VARINT
26659/*
26660 * Date built-ins
26661 *
26662 * Unlike most built-ins, Date has some platform dependencies for getting
26663 * UTC time, converting between UTC and local time, and parsing and
26664 * formatting time values. These are all abstracted behind DUK_USE_xxx
26665 * config options. There are built-in platform specific providers for
26666 * POSIX and Windows, but external providers can also be used.
26667 *
26668 * See doc/datetime.rst.
26669 *
26670 */
26671
26672/* #include duk_internal.h -> already included */
26673
26674/* XXX: currently defines unnecessary symbols when DUK_USE_DATE_BUILTIN is disabled. */
26675
26676/*
26677 * Forward declarations
26678 */
26679
26680DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval_tzoffset(duk_context *ctx, duk_small_uint_t flags, duk_int_t *out_tzoffset);
26681DUK_LOCAL_DECL duk_double_t duk__push_this_get_timeval(duk_context *ctx, duk_small_uint_t flags);
26682DUK_LOCAL_DECL void duk__twodigit_year_fixup(duk_context *ctx, duk_idx_t idx_val);
26683DUK_LOCAL_DECL duk_ret_t duk__set_this_timeval_from_dparts(duk_context *ctx, duk_double_t *dparts, duk_small_uint_t flags);
26684
26685/*
26686 * Other file level defines
26687 */
26688
26689/* Debug macro to print all parts and dparts (used manually because of debug level). */
26690#define DUK__DPRINT_PARTS_AND_DPARTS(parts,dparts) do { \
26691 DUK_D(DUK_DPRINT("parts: %ld %ld %ld %ld %ld %ld %ld %ld, dparts: %lf %lf %lf %lf %lf %lf %lf %lf", \
26692 (long) (parts)[0], (long) (parts)[1], \
26693 (long) (parts)[2], (long) (parts)[3], \
26694 (long) (parts)[4], (long) (parts)[5], \
26695 (long) (parts)[6], (long) (parts)[7], \
26696 (double) (dparts)[0], (double) (dparts)[1], \
26697 (double) (dparts)[2], (double) (dparts)[3], \
26698 (double) (dparts)[4], (double) (dparts)[5], \
26699 (double) (dparts)[6], (double) (dparts)[7])); \
26700 } while (0)
26701#define DUK__DPRINT_PARTS(parts) do { \
26702 DUK_D(DUK_DPRINT("parts: %ld %ld %ld %ld %ld %ld %ld %ld", \
26703 (long) (parts)[0], (long) (parts)[1], \
26704 (long) (parts)[2], (long) (parts)[3], \
26705 (long) (parts)[4], (long) (parts)[5], \
26706 (long) (parts)[6], (long) (parts)[7])); \
26707 } while (0)
26708#define DUK__DPRINT_DPARTS(dparts) do { \
26709 DUK_D(DUK_DPRINT("dparts: %lf %lf %lf %lf %lf %lf %lf %lf", \
26710 (double) (dparts)[0], (double) (dparts)[1], \
26711 (double) (dparts)[2], (double) (dparts)[3], \
26712 (double) (dparts)[4], (double) (dparts)[5], \
26713 (double) (dparts)[6], (double) (dparts)[7])); \
26714 } while (0)
26715
26716/* Equivalent year for DST calculations outside [1970,2038[ range, see
26717 * E5 Section 15.9.1.8. Equivalent year has the same leap-year-ness and
26718 * starts with the same weekday on Jan 1.
26719 * https://bugzilla.mozilla.org/show_bug.cgi?id=351066
26720 */
26721#define DUK__YEAR(x) ((duk_uint8_t) ((x) - 1970))
26722DUK_LOCAL duk_uint8_t duk__date_equivyear[14] = {
26723#if 1
26724 /* This is based on V8 EquivalentYear() algorithm (see util/genequivyear.py):
26725 * http://code.google.com/p/v8/source/browse/trunk/src/date.h#146
26726 */
26727
26728 /* non-leap year: sunday, monday, ... */
26729 DUK__YEAR(2023), DUK__YEAR(2035), DUK__YEAR(2019), DUK__YEAR(2031),
26730 DUK__YEAR(2015), DUK__YEAR(2027), DUK__YEAR(2011),
26731
26732 /* leap year: sunday, monday, ... */
26733 DUK__YEAR(2012), DUK__YEAR(2024), DUK__YEAR(2008), DUK__YEAR(2020),
26734 DUK__YEAR(2032), DUK__YEAR(2016), DUK__YEAR(2028)
26735#endif
26736
26737#if 0
26738 /* This is based on Rhino EquivalentYear() algorithm:
26739 * https://github.com/mozilla/rhino/blob/f99cc11d616f0cdda2c42bde72b3484df6182947/src/org/mozilla/javascript/NativeDate.java
26740 */
26741
26742 /* non-leap year: sunday, monday, ... */
26743 DUK__YEAR(1978), DUK__YEAR(1973), DUK__YEAR(1985), DUK__YEAR(1986),
26744 DUK__YEAR(1981), DUK__YEAR(1971), DUK__YEAR(1977),
26745
26746 /* leap year: sunday, monday, ... */
26747 DUK__YEAR(1984), DUK__YEAR(1996), DUK__YEAR(1980), DUK__YEAR(1992),
26748 DUK__YEAR(1976), DUK__YEAR(1988), DUK__YEAR(1972)
26749#endif
26750};
26751
26752/*
26753 * ISO 8601 subset parser.
26754 */
26755
26756/* Parser part count. */
26757#define DUK__NUM_ISO8601_PARSER_PARTS 9
26758
26759/* Parser part indices. */
26760#define DUK__PI_YEAR 0
26761#define DUK__PI_MONTH 1
26762#define DUK__PI_DAY 2
26763#define DUK__PI_HOUR 3
26764#define DUK__PI_MINUTE 4
26765#define DUK__PI_SECOND 5
26766#define DUK__PI_MILLISECOND 6
26767#define DUK__PI_TZHOUR 7
26768#define DUK__PI_TZMINUTE 8
26769
26770/* Parser part masks. */
26771#define DUK__PM_YEAR (1 << DUK__PI_YEAR)
26772#define DUK__PM_MONTH (1 << DUK__PI_MONTH)
26773#define DUK__PM_DAY (1 << DUK__PI_DAY)
26774#define DUK__PM_HOUR (1 << DUK__PI_HOUR)
26775#define DUK__PM_MINUTE (1 << DUK__PI_MINUTE)
26776#define DUK__PM_SECOND (1 << DUK__PI_SECOND)
26777#define DUK__PM_MILLISECOND (1 << DUK__PI_MILLISECOND)
26778#define DUK__PM_TZHOUR (1 << DUK__PI_TZHOUR)
26779#define DUK__PM_TZMINUTE (1 << DUK__PI_TZMINUTE)
26780
26781/* Parser separator indices. */
26782#define DUK__SI_PLUS 0
26783#define DUK__SI_MINUS 1
26784#define DUK__SI_T 2
26785#define DUK__SI_SPACE 3
26786#define DUK__SI_COLON 4
26787#define DUK__SI_PERIOD 5
26788#define DUK__SI_Z 6
26789#define DUK__SI_NUL 7
26790
26791/* Parser separator masks. */
26792#define DUK__SM_PLUS (1 << DUK__SI_PLUS)
26793#define DUK__SM_MINUS (1 << DUK__SI_MINUS)
26794#define DUK__SM_T (1 << DUK__SI_T)
26795#define DUK__SM_SPACE (1 << DUK__SI_SPACE)
26796#define DUK__SM_COLON (1 << DUK__SI_COLON)
26797#define DUK__SM_PERIOD (1 << DUK__SI_PERIOD)
26798#define DUK__SM_Z (1 << DUK__SI_Z)
26799#define DUK__SM_NUL (1 << DUK__SI_NUL)
26800
26801/* Rule control flags. */
26802#define DUK__CF_NEG (1 << 0) /* continue matching, set neg_tzoffset flag */
26803#define DUK__CF_ACCEPT (1 << 1) /* accept string */
26804#define DUK__CF_ACCEPT_NUL (1 << 2) /* accept string if next char is NUL (otherwise reject) */
26805
26806#define DUK__PACK_RULE(partmask,sepmask,nextpart,flags) \
26807 ((duk_uint32_t) (partmask) + \
26808 (((duk_uint32_t) (sepmask)) << 9) + \
26809 (((duk_uint32_t) (nextpart)) << 17) + \
26810 (((duk_uint32_t) (flags)) << 21))
26811
26812#define DUK__UNPACK_RULE(rule,var_nextidx,var_flags) do { \
26813 (var_nextidx) = (duk_small_uint_t) (((rule) >> 17) & 0x0f); \
26814 (var_flags) = (duk_small_uint_t) ((rule) >> 21); \
26815 } while (0)
26816
26817#define DUK__RULE_MASK_PART_SEP 0x1ffffUL
26818
26819/* Matching separator index is used in the control table */
26820DUK_LOCAL const duk_uint8_t duk__parse_iso8601_seps[] = {
26821 DUK_ASC_PLUS /*0*/, DUK_ASC_MINUS /*1*/, DUK_ASC_UC_T /*2*/, DUK_ASC_SPACE /*3*/,
26822 DUK_ASC_COLON /*4*/, DUK_ASC_PERIOD /*5*/, DUK_ASC_UC_Z /*6*/, DUK_ASC_NUL /*7*/
26823};
26824
26825/* Rule table: first matching rule is used to determine what to do next. */
26826DUK_LOCAL const duk_uint32_t duk__parse_iso8601_control[] = {
26827 DUK__PACK_RULE(DUK__PM_YEAR, DUK__SM_MINUS, DUK__PI_MONTH, 0),
26828 DUK__PACK_RULE(DUK__PM_MONTH, DUK__SM_MINUS, DUK__PI_DAY, 0),
26829 DUK__PACK_RULE(DUK__PM_YEAR | DUK__PM_MONTH | DUK__PM_DAY, DUK__SM_T | DUK__SM_SPACE, DUK__PI_HOUR, 0),
26830 DUK__PACK_RULE(DUK__PM_HOUR, DUK__SM_COLON, DUK__PI_MINUTE, 0),
26831 DUK__PACK_RULE(DUK__PM_MINUTE, DUK__SM_COLON, DUK__PI_SECOND, 0),
26832 DUK__PACK_RULE(DUK__PM_SECOND, DUK__SM_PERIOD, DUK__PI_MILLISECOND, 0),
26833 DUK__PACK_RULE(DUK__PM_TZHOUR, DUK__SM_COLON, DUK__PI_TZMINUTE, 0),
26834 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),
26835 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),
26836 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),
26837 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)
26838
26839 /* Note1: the specification doesn't require matching a time form with
26840 * just hours ("HH"), but we accept it here, e.g. "2012-01-02T12Z".
26841 *
26842 * Note2: the specification doesn't require matching a timezone offset
26843 * with just hours ("HH"), but accept it here, e.g. "2012-01-02T03:04:05+02"
26844 */
26845};
26846
26847DUK_LOCAL duk_bool_t duk__parse_string_iso8601_subset(duk_context *ctx, const char *str) {
26848 duk_int_t parts[DUK__NUM_ISO8601_PARSER_PARTS];
26849 duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
26850 duk_double_t d;
26851 const duk_uint8_t *p;
26852 duk_small_uint_t part_idx = 0;
26853 duk_int_t accum = 0;
26854 duk_small_uint_t ndigits = 0;
26855 duk_bool_t neg_year = 0;
26856 duk_bool_t neg_tzoffset = 0;
26857 duk_uint_fast8_t ch;
26858 duk_small_uint_t i;
26859
26860 /* During parsing, month and day are one-based; set defaults here. */
26861 DUK_MEMZERO(parts, sizeof(parts));
26862 DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] == 0); /* don't care value, year is mandatory */
26863 parts[DUK_DATE_IDX_MONTH] = 1;
26864 parts[DUK_DATE_IDX_DAY] = 1;
26865
26866 /* Special handling for year sign. */
26867 p = (const duk_uint8_t *) str;
26868 ch = p[0];
26869 if (ch == DUK_ASC_PLUS) {
26870 p++;
26871 } else if (ch == DUK_ASC_MINUS) {
26872 neg_year = 1;
26873 p++;
26874 }
26875
26876 for (;;) {
26877 ch = *p++;
26878 DUK_DDD(DUK_DDDPRINT("parsing, part_idx=%ld, char=%ld ('%c')",
26879 (long) part_idx, (long) ch,
26880 (int) ((ch >= 0x20 && ch <= 0x7e) ? ch : DUK_ASC_QUESTION)));
26881
26882 if (ch >= DUK_ASC_0 && ch <= DUK_ASC_9) {
26883 if (ndigits >= 9) {
26884 DUK_DDD(DUK_DDDPRINT("too many digits -> reject"));
26885 goto reject;
26886 }
26887 if (part_idx == DUK__PI_MILLISECOND && ndigits >= 3) {
26888 /* ignore millisecond fractions after 3 */
26889 } else {
26890 accum = accum * 10 + ((duk_int_t) ch) - ((duk_int_t) DUK_ASC_0) + 0x00;
26891 ndigits++;
26892 }
26893 } else {
26894 duk_uint_fast32_t match_val;
26895 duk_small_int_t sep_idx;
26896
26897 if (ndigits <= 0) {
26898 goto reject;
26899 }
26900 if (part_idx == DUK__PI_MILLISECOND) {
26901 /* complete the millisecond field */
26902 while (ndigits < 3) {
26903 accum *= 10;
26904 ndigits++;
26905 }
26906 }
26907 parts[part_idx] = accum;
26908 DUK_DDD(DUK_DDDPRINT("wrote part %ld -> value %ld", (long) part_idx, (long) accum));
26909
26910 accum = 0;
26911 ndigits = 0;
26912
26913 for (i = 0; i < (duk_small_uint_t) (sizeof(duk__parse_iso8601_seps) / sizeof(duk_uint8_t)); i++) {
26914 if (duk__parse_iso8601_seps[i] == ch) {
26915 break;
26916 }
26917 }
26918 if (i == (duk_small_uint_t) (sizeof(duk__parse_iso8601_seps) / sizeof(duk_uint8_t))) {
26919 DUK_DDD(DUK_DDDPRINT("separator character doesn't match -> reject"));
26920 goto reject;
26921 }
26922
26923 sep_idx = i;
26924 match_val = (1UL << part_idx) + (1UL << (sep_idx + 9)); /* match against rule part/sep bits */
26925
26926 for (i = 0; i < (duk_small_uint_t) (sizeof(duk__parse_iso8601_control) / sizeof(duk_uint32_t)); i++) {
26927 duk_uint_fast32_t rule = duk__parse_iso8601_control[i];
26928 duk_small_uint_t nextpart;
26929 duk_small_uint_t cflags;
26930
26931 DUK_DDD(DUK_DDDPRINT("part_idx=%ld, sep_idx=%ld, match_val=0x%08lx, considering rule=0x%08lx",
26932 (long) part_idx, (long) sep_idx,
26933 (unsigned long) match_val, (unsigned long) rule));
26934
26935 if ((rule & match_val) != match_val) {
26936 continue;
26937 }
26938
26939 DUK__UNPACK_RULE(rule, nextpart, cflags);
26940
26941 DUK_DDD(DUK_DDDPRINT("rule match -> part_idx=%ld, sep_idx=%ld, match_val=0x%08lx, "
26942 "rule=0x%08lx -> nextpart=%ld, cflags=0x%02lx",
26943 (long) part_idx, (long) sep_idx,
26944 (unsigned long) match_val, (unsigned long) rule,
26945 (long) nextpart, (unsigned long) cflags));
26946
26947 if (cflags & DUK__CF_NEG) {
26948 neg_tzoffset = 1;
26949 }
26950
26951 if (cflags & DUK__CF_ACCEPT) {
26952 goto accept;
26953 }
26954
26955 if (cflags & DUK__CF_ACCEPT_NUL) {
26956 DUK_ASSERT(*(p - 1) != (char) 0);
26957 if (*p == DUK_ASC_NUL) {
26958 goto accept;
26959 }
26960 goto reject;
26961 }
26962
26963 part_idx = nextpart;
26964 break;
26965 } /* rule match */
26966
26967 if (i == (duk_small_uint_t) (sizeof(duk__parse_iso8601_control) / sizeof(duk_uint32_t))) {
26968 DUK_DDD(DUK_DDDPRINT("no rule matches -> reject"));
26969 goto reject;
26970 }
26971
26972 if (ch == 0) {
26973 /* This shouldn't be necessary, but check just in case
26974 * to avoid any chance of overruns.
26975 */
26976 DUK_DDD(DUK_DDDPRINT("NUL after rule matching (should not happen) -> reject"));
26977 goto reject;
26978 }
26979 } /* if-digit-else-ctrl */
26980 } /* char loop */
26981
26982 /* We should never exit the loop above. */
26983 DUK_UNREACHABLE();
26984
26985 reject:
26986 DUK_DDD(DUK_DDDPRINT("reject"));
26987 return 0;
26988
26989 accept:
26990 DUK_DDD(DUK_DDDPRINT("accept"));
26991
26992 /* Apply timezone offset to get the main parts in UTC */
26993 if (neg_year) {
26994 parts[DUK__PI_YEAR] = -parts[DUK__PI_YEAR];
26995 }
26996 if (neg_tzoffset) {
26997 parts[DUK__PI_HOUR] += parts[DUK__PI_TZHOUR];
26998 parts[DUK__PI_MINUTE] += parts[DUK__PI_TZMINUTE];
26999 } else {
27000 parts[DUK__PI_HOUR] -= parts[DUK__PI_TZHOUR];
27001 parts[DUK__PI_MINUTE] -= parts[DUK__PI_TZMINUTE];
27002 }
27003 parts[DUK__PI_MONTH] -= 1; /* zero-based month */
27004 parts[DUK__PI_DAY] -= 1; /* zero-based day */
27005
27006 /* Use double parts, they tolerate unnormalized time.
27007 *
27008 * Note: DUK_DATE_IDX_WEEKDAY is initialized with a bogus value (DUK__PI_TZHOUR)
27009 * on purpose. It won't be actually used by duk_bi_date_get_timeval_from_dparts(),
27010 * but will make the value initialized just in case, and avoid any
27011 * potential for Valgrind issues.
27012 */
27013 for (i = 0; i < DUK_DATE_IDX_NUM_PARTS; i++) {
27014 DUK_DDD(DUK_DDDPRINT("part[%ld] = %ld", (long) i, (long) parts[i]));
27015 dparts[i] = parts[i];
27016 }
27017
27018 d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
27019 duk_push_number(ctx, d);
27020 return 1;
27021}
27022
27023/*
27024 * Date/time parsing helper.
27025 *
27026 * Parse a datetime string into a time value. We must first try to parse
27027 * the input according to the standard format in E5.1 Section 15.9.1.15.
27028 * If that fails, we can try to parse using custom parsing, which can
27029 * either be platform neutral (custom code) or platform specific (using
27030 * existing platform API calls).
27031 *
27032 * Note in particular that we must parse whatever toString(), toUTCString(),
27033 * and toISOString() can produce; see E5.1 Section 15.9.4.2.
27034 *
27035 * Returns 1 to allow tail calling.
27036 *
27037 * There is much room for improvement here with respect to supporting
27038 * alternative datetime formats. For instance, V8 parses '2012-01-01' as
27039 * UTC and '2012/01/01' as local time.
27040 */
27041
27042DUK_LOCAL duk_ret_t duk__parse_string(duk_context *ctx, const char *str) {
27043 /* XXX: there is a small risk here: because the ISO 8601 parser is
27044 * very loose, it may end up parsing some datetime values which
27045 * would be better parsed with a platform specific parser.
27046 */
27047
27048 DUK_ASSERT(str != NULL);
27049 DUK_DDD(DUK_DDDPRINT("parse datetime from string '%s'", (const char *) str));
27050
27051 if (duk__parse_string_iso8601_subset(ctx, str) != 0) {
27052 return 1;
27053 }
27054
27055#if defined(DUK_USE_DATE_PARSE_STRING)
27056 /* Contract, either:
27057 * - Push value on stack and return 1
27058 * - Don't push anything on stack and return 0
27059 */
27060
27061 if (DUK_USE_DATE_PARSE_STRING(ctx, str) != 0) {
27062 return 1;
27063 }
27064#else
27065 /* No platform-specific parsing, this is not an error. */
27066#endif
27067
27068 duk_push_nan(ctx);
27069 return 1;
27070}
27071
27072/*
27073 * Calendar helpers
27074 *
27075 * Some helpers are used for getters and can operate on normalized values
27076 * which can be represented with 32-bit signed integers. Other helpers are
27077 * needed by setters and operate on un-normalized double values, must watch
27078 * out for non-finite numbers etc.
27079 */
27080
27081DUK_LOCAL duk_uint8_t duk__days_in_month[12] = {
27082 (duk_uint8_t) 31, (duk_uint8_t) 28, (duk_uint8_t) 31, (duk_uint8_t) 30,
27083 (duk_uint8_t) 31, (duk_uint8_t) 30, (duk_uint8_t) 31, (duk_uint8_t) 31,
27084 (duk_uint8_t) 30, (duk_uint8_t) 31, (duk_uint8_t) 30, (duk_uint8_t) 31
27085};
27086
27087/* Maximum iteration count for computing UTC-to-local time offset when
27088 * creating an Ecmascript time value from local parts.
27089 */
27090#define DUK__LOCAL_TZOFFSET_MAXITER 4
27091
27092/* Because 'day since epoch' can be negative and is used to compute weekday
27093 * using a modulo operation, add this multiple of 7 to avoid negative values
27094 * when year is below 1970 epoch. Ecmascript time values are restricted to
27095 * +/- 100 million days from epoch, so this adder fits nicely into 32 bits.
27096 * Round to a multiple of 7 (= floor(100000000 / 7) * 7) and add margin.
27097 */
27098#define DUK__WEEKDAY_MOD_ADDER (20000000 * 7) /* 0x08583b00 */
27099
27100DUK_INTERNAL duk_bool_t duk_bi_date_is_leap_year(duk_int_t year) {
27101 if ((year % 4) != 0) {
27102 return 0;
27103 }
27104 if ((year % 100) != 0) {
27105 return 1;
27106 }
27107 if ((year % 400) != 0) {
27108 return 0;
27109 }
27110 return 1;
27111}
27112
27113DUK_INTERNAL duk_bool_t duk_bi_date_timeval_in_valid_range(duk_double_t x) {
27114 return (x >= -DUK_DATE_MSEC_100M_DAYS && x <= DUK_DATE_MSEC_100M_DAYS);
27115}
27116
27117DUK_INTERNAL duk_bool_t duk_bi_date_timeval_in_leeway_range(duk_double_t x) {
27118 return (x >= -DUK_DATE_MSEC_100M_DAYS_LEEWAY && x <= DUK_DATE_MSEC_100M_DAYS_LEEWAY);
27119}
27120
27121DUK_INTERNAL duk_bool_t duk_bi_date_year_in_valid_range(duk_double_t x) {
27122 return (x >= DUK_DATE_MIN_ECMA_YEAR && x <= DUK_DATE_MAX_ECMA_YEAR);
27123}
27124
27125DUK_LOCAL duk_double_t duk__timeclip(duk_double_t x) {
27126 if (!DUK_ISFINITE(x)) {
27127 return DUK_DOUBLE_NAN;
27128 }
27129
27130 if (!duk_bi_date_timeval_in_valid_range(x)) {
27131 return DUK_DOUBLE_NAN;
27132 }
27133
27134 x = duk_js_tointeger_number(x);
27135
27136 /* Here we'd have the option to normalize -0 to +0. */
27137 return x;
27138}
27139
27140/* Integer division which floors also negative values correctly. */
27141DUK_LOCAL duk_int_t duk__div_floor(duk_int_t a, duk_int_t b) {
27142 DUK_ASSERT(b > 0);
27143 if (a >= 0) {
27144 return a / b;
27145 } else {
27146 /* e.g. a = -4, b = 5 --> -4 - 5 + 1 / 5 --> -8 / 5 --> -1
27147 * a = -5, b = 5 --> -5 - 5 + 1 / 5 --> -9 / 5 --> -1
27148 * a = -6, b = 5 --> -6 - 5 + 1 / 5 --> -10 / 5 --> -2
27149 */
27150 return (a - b + 1) / b;
27151 }
27152}
27153
27154/* Compute day number of the first day of a given year. */
27155DUK_LOCAL duk_int_t duk__day_from_year(duk_int_t year) {
27156 /* Note: in integer arithmetic, (x / 4) is same as floor(x / 4) for non-negative
27157 * values, but is incorrect for negative ones.
27158 */
27159 return 365 * (year - 1970)
27160 + duk__div_floor(year - 1969, 4)
27161 - duk__div_floor(year - 1901, 100)
27162 + duk__div_floor(year - 1601, 400);
27163}
27164
27165/* Given a day number, determine year and day-within-year. */
27166DUK_LOCAL duk_int_t duk__year_from_day(duk_int_t day, duk_small_int_t *out_day_within_year) {
27167 duk_int_t year;
27168 duk_int_t diff_days;
27169
27170 /* estimate year upwards (towards positive infinity), then back down;
27171 * two iterations should be enough
27172 */
27173
27174 if (day >= 0) {
27175 year = 1970 + day / 365;
27176 } else {
27177 year = 1970 + day / 366;
27178 }
27179
27180 for (;;) {
27181 diff_days = duk__day_from_year(year) - day;
27182 DUK_DDD(DUK_DDDPRINT("year=%ld day=%ld, diff_days=%ld", (long) year, (long) day, (long) diff_days));
27183 if (diff_days <= 0) {
27184 DUK_ASSERT(-diff_days < 366); /* fits into duk_small_int_t */
27185 *out_day_within_year = -diff_days;
27186 DUK_DDD(DUK_DDDPRINT("--> year=%ld, day-within-year=%ld",
27187 (long) year, (long) *out_day_within_year));
27188 DUK_ASSERT(*out_day_within_year >= 0);
27189 DUK_ASSERT(*out_day_within_year < (duk_bi_date_is_leap_year(year) ? 366 : 365));
27190 return year;
27191 }
27192
27193 /* Note: this is very tricky; we must never 'overshoot' the
27194 * correction downwards.
27195 */
27196 year -= 1 + (diff_days - 1) / 366; /* conservative */
27197 }
27198}
27199
27200/* Given a (year, month, day-within-month) triple, compute day number.
27201 * The input triple is un-normalized and may contain non-finite values.
27202 */
27203DUK_LOCAL duk_double_t duk__make_day(duk_double_t year, duk_double_t month, duk_double_t day) {
27204 duk_int_t day_num;
27205 duk_bool_t is_leap;
27206 duk_small_int_t i, n;
27207
27208 /* Assume that year, month, day are all coerced to whole numbers.
27209 * They may also be NaN or infinity, in which case this function
27210 * must return NaN or infinity to ensure time value becomes NaN.
27211 * If 'day' is NaN, the final return will end up returning a NaN,
27212 * so it doesn't need to be checked here.
27213 */
27214
27215 if (!DUK_ISFINITE(year) || !DUK_ISFINITE(month)) {
27216 return DUK_DOUBLE_NAN;
27217 }
27218
27219 year += DUK_FLOOR(month / 12.0);
27220
27221 month = DUK_FMOD(month, 12.0);
27222 if (month < 0.0) {
27223 /* handle negative values */
27224 month += 12.0;
27225 }
27226
27227 /* The algorithm in E5.1 Section 15.9.1.12 normalizes month, but
27228 * does not normalize the day-of-month (nor check whether or not
27229 * it is finite) because it's not necessary for finding the day
27230 * number which matches the (year,month) pair.
27231 *
27232 * We assume that duk__day_from_year() is exact here.
27233 *
27234 * Without an explicit infinity / NaN check in the beginning,
27235 * day_num would be a bogus integer here.
27236 *
27237 * It's possible for 'year' to be out of integer range here.
27238 * If so, we need to return NaN without integer overflow.
27239 * This fixes test-bug-setyear-overflow.js.
27240 */
27241
27242 if (!duk_bi_date_year_in_valid_range(year)) {
27243 DUK_DD(DUK_DDPRINT("year not in ecmascript valid range, avoid integer overflow: %lf", (double) year));
27244 return DUK_DOUBLE_NAN;
27245 }
27246 day_num = duk__day_from_year((duk_int_t) year);
27247 is_leap = duk_bi_date_is_leap_year((duk_int_t) year);
27248
27249 n = (duk_small_int_t) month;
27250 for (i = 0; i < n; i++) {
27251 day_num += duk__days_in_month[i];
27252 if (i == 1 && is_leap) {
27253 day_num++;
27254 }
27255 }
27256
27257 /* If 'day' is NaN, returns NaN. */
27258 return (duk_double_t) day_num + day;
27259}
27260
27261/* Split time value into parts. The time value is assumed to be an internal
27262 * one, i.e. finite, no fractions. Possible local time adjustment has already
27263 * been applied when reading the time value.
27264 */
27265DUK_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) {
27266 duk_double_t d1, d2;
27267 duk_int_t t1, t2;
27268 duk_int_t day_since_epoch;
27269 duk_int_t year; /* does not fit into 16 bits */
27270 duk_small_int_t day_in_year;
27271 duk_small_int_t month;
27272 duk_small_int_t day;
27273 duk_small_int_t dim;
27274 duk_int_t jan1_since_epoch;
27275 duk_small_int_t jan1_weekday;
27276 duk_int_t equiv_year;
27277 duk_small_uint_t i;
27278 duk_bool_t is_leap;
27279 duk_small_int_t arridx;
27280
27281 DUK_ASSERT(DUK_ISFINITE(d)); /* caller checks */
27282 DUK_ASSERT(DUK_FLOOR(d) == d); /* no fractions in internal time */
27283
27284 /* The timevalue must be in valid Ecmascript range, but since a local
27285 * time offset can be applied, we need to allow a +/- 24h leeway to
27286 * the value. In other words, although the UTC time is within the
27287 * Ecmascript range, the local part values can be just outside of it.
27288 */
27289 DUK_UNREF(duk_bi_date_timeval_in_leeway_range);
27290 DUK_ASSERT(duk_bi_date_timeval_in_leeway_range(d));
27291
27292 /* these computations are guaranteed to be exact for the valid
27293 * E5 time value range, assuming milliseconds without fractions.
27294 */
27295 d1 = (duk_double_t) DUK_FMOD(d, (double) DUK_DATE_MSEC_DAY);
27296 if (d1 < 0.0) {
27297 /* deal with negative values */
27298 d1 += (duk_double_t) DUK_DATE_MSEC_DAY;
27299 }
27300 d2 = DUK_FLOOR((double) (d / (duk_double_t) DUK_DATE_MSEC_DAY));
27301 DUK_ASSERT(d2 * ((duk_double_t) DUK_DATE_MSEC_DAY) + d1 == d);
27302 /* now expected to fit into a 32-bit integer */
27303 t1 = (duk_int_t) d1;
27304 t2 = (duk_int_t) d2;
27305 day_since_epoch = t2;
27306 DUK_ASSERT((duk_double_t) t1 == d1);
27307 DUK_ASSERT((duk_double_t) t2 == d2);
27308
27309 /* t1 = milliseconds within day (fits 32 bit)
27310 * t2 = day number from epoch (fits 32 bit, may be negative)
27311 */
27312
27313 parts[DUK_DATE_IDX_MILLISECOND] = t1 % 1000; t1 /= 1000;
27314 parts[DUK_DATE_IDX_SECOND] = t1 % 60; t1 /= 60;
27315 parts[DUK_DATE_IDX_MINUTE] = t1 % 60; t1 /= 60;
27316 parts[DUK_DATE_IDX_HOUR] = t1;
27317 DUK_ASSERT(parts[DUK_DATE_IDX_MILLISECOND] >= 0 && parts[DUK_DATE_IDX_MILLISECOND] <= 999);
27318 DUK_ASSERT(parts[DUK_DATE_IDX_SECOND] >= 0 && parts[DUK_DATE_IDX_SECOND] <= 59);
27319 DUK_ASSERT(parts[DUK_DATE_IDX_MINUTE] >= 0 && parts[DUK_DATE_IDX_MINUTE] <= 59);
27320 DUK_ASSERT(parts[DUK_DATE_IDX_HOUR] >= 0 && parts[DUK_DATE_IDX_HOUR] <= 23);
27321
27322 DUK_DDD(DUK_DDDPRINT("d=%lf, d1=%lf, d2=%lf, t1=%ld, t2=%ld, parts: hour=%ld min=%ld sec=%ld msec=%ld",
27323 (double) d, (double) d1, (double) d2, (long) t1, (long) t2,
27324 (long) parts[DUK_DATE_IDX_HOUR],
27325 (long) parts[DUK_DATE_IDX_MINUTE],
27326 (long) parts[DUK_DATE_IDX_SECOND],
27327 (long) parts[DUK_DATE_IDX_MILLISECOND]));
27328
27329 /* This assert depends on the input parts representing time inside
27330 * the Ecmascript range.
27331 */
27332 DUK_ASSERT(t2 + DUK__WEEKDAY_MOD_ADDER >= 0);
27333 parts[DUK_DATE_IDX_WEEKDAY] = (t2 + 4 + DUK__WEEKDAY_MOD_ADDER) % 7; /* E5.1 Section 15.9.1.6 */
27334 DUK_ASSERT(parts[DUK_DATE_IDX_WEEKDAY] >= 0 && parts[DUK_DATE_IDX_WEEKDAY] <= 6);
27335
27336 year = duk__year_from_day(t2, &day_in_year);
27337 day = day_in_year;
27338 is_leap = duk_bi_date_is_leap_year(year);
27339 for (month = 0; month < 12; month++) {
27340 dim = duk__days_in_month[month];
27341 if (month == 1 && is_leap) {
27342 dim++;
27343 }
27344 DUK_DDD(DUK_DDDPRINT("month=%ld, dim=%ld, day=%ld",
27345 (long) month, (long) dim, (long) day));
27346 if (day < dim) {
27347 break;
27348 }
27349 day -= dim;
27350 }
27351 DUK_DDD(DUK_DDDPRINT("final month=%ld", (long) month));
27352 DUK_ASSERT(month >= 0 && month <= 11);
27353 DUK_ASSERT(day >= 0 && day <= 31);
27354
27355 /* Equivalent year mapping, used to avoid DST trouble when platform
27356 * may fail to provide reasonable DST answers for dates outside the
27357 * ordinary range (e.g. 1970-2038). An equivalent year has the same
27358 * leap-year-ness as the original year and begins on the same weekday
27359 * (Jan 1).
27360 *
27361 * The year 2038 is avoided because there seem to be problems with it
27362 * on some platforms. The year 1970 is also avoided as there were
27363 * practical problems with it; an equivalent year is used for it too,
27364 * which breaks some DST computations for 1970 right now, see e.g.
27365 * test-bi-date-tzoffset-brute-fi.js.
27366 */
27367 if ((flags & DUK_DATE_FLAG_EQUIVYEAR) && (year < 1971 || year > 2037)) {
27368 DUK_ASSERT(is_leap == 0 || is_leap == 1);
27369
27370 jan1_since_epoch = day_since_epoch - day_in_year; /* day number for Jan 1 since epoch */
27371 DUK_ASSERT(jan1_since_epoch + DUK__WEEKDAY_MOD_ADDER >= 0);
27372 jan1_weekday = (jan1_since_epoch + 4 + DUK__WEEKDAY_MOD_ADDER) % 7; /* E5.1 Section 15.9.1.6 */
27373 DUK_ASSERT(jan1_weekday >= 0 && jan1_weekday <= 6);
27374 arridx = jan1_weekday;
27375 if (is_leap) {
27376 arridx += 7;
27377 }
27378 DUK_ASSERT(arridx >= 0 && arridx < (duk_small_int_t) (sizeof(duk__date_equivyear) / sizeof(duk_uint8_t)));
27379
27380 equiv_year = (duk_int_t) duk__date_equivyear[arridx] + 1970;
27381 year = equiv_year;
27382 DUK_DDD(DUK_DDDPRINT("equiv year mapping, year=%ld, day_in_year=%ld, day_since_epoch=%ld, "
27383 "jan1_since_epoch=%ld, jan1_weekday=%ld -> equiv year %ld",
27384 (long) year, (long) day_in_year, (long) day_since_epoch,
27385 (long) jan1_since_epoch, (long) jan1_weekday, (long) equiv_year));
27386 }
27387
27388 parts[DUK_DATE_IDX_YEAR] = year;
27389 parts[DUK_DATE_IDX_MONTH] = month;
27390 parts[DUK_DATE_IDX_DAY] = day;
27391
27392 if (flags & DUK_DATE_FLAG_ONEBASED) {
27393 parts[DUK_DATE_IDX_MONTH]++; /* zero-based -> one-based */
27394 parts[DUK_DATE_IDX_DAY]++; /* -""- */
27395 }
27396
27397 if (dparts != NULL) {
27398 for (i = 0; i < DUK_DATE_IDX_NUM_PARTS; i++) {
27399 dparts[i] = (duk_double_t) parts[i];
27400 }
27401 }
27402}
27403
27404/* Compute time value from (double) parts. The parts can be either UTC
27405 * or local time; if local, they need to be (conceptually) converted into
27406 * UTC time. The parts may represent valid or invalid time, and may be
27407 * wildly out of range (but may cancel each other and still come out in
27408 * the valid Date range).
27409 */
27410DUK_INTERNAL duk_double_t duk_bi_date_get_timeval_from_dparts(duk_double_t *dparts, duk_small_uint_t flags) {
27411#if defined(DUK_USE_PARANOID_DATE_COMPUTATION)
27412 /* See comments below on MakeTime why these are volatile. */
27413 volatile duk_double_t tmp_time;
27414 volatile duk_double_t tmp_day;
27415 volatile duk_double_t d;
27416#else
27417 duk_double_t tmp_time;
27418 duk_double_t tmp_day;
27419 duk_double_t d;
27420#endif
27421 duk_small_uint_t i;
27422 duk_int_t tzoff, tzoffprev1, tzoffprev2;
27423
27424 /* Expects 'this' at top of stack on entry. */
27425
27426 /* Coerce all finite parts with ToInteger(). ToInteger() must not
27427 * be called for NaN/Infinity because it will convert e.g. NaN to
27428 * zero. If ToInteger() has already been called, this has no side
27429 * effects and is idempotent.
27430 *
27431 * Don't read dparts[DUK_DATE_IDX_WEEKDAY]; it will cause Valgrind
27432 * issues if the value is uninitialized.
27433 */
27434 for (i = 0; i <= DUK_DATE_IDX_MILLISECOND; i++) {
27435 /* SCANBUILD: scan-build complains here about assigned value
27436 * being garbage or undefined. This is correct but operating
27437 * on undefined values has no ill effect and is ignored by the
27438 * caller in the case where this happens.
27439 */
27440 d = dparts[i];
27441 if (DUK_ISFINITE(d)) {
27442 dparts[i] = duk_js_tointeger_number(d);
27443 }
27444 }
27445
27446 /* Use explicit steps in computation to try to ensure that
27447 * computation happens with intermediate results coerced to
27448 * double values (instead of using something more accurate).
27449 * E.g. E5.1 Section 15.9.1.11 requires use of IEEE 754
27450 * rules (= Ecmascript '+' and '*' operators).
27451 *
27452 * Without 'volatile' even this approach fails on some platform
27453 * and compiler combinations. For instance, gcc 4.8.1 on Ubuntu
27454 * 64-bit, with -m32 and without -std=c99, test-bi-date-canceling.js
27455 * would fail because of some optimizations when computing tmp_time
27456 * (MakeTime below). Adding 'volatile' to tmp_time solved this
27457 * particular problem (annoyingly, also adding debug prints or
27458 * running the executable under valgrind hides it).
27459 */
27460
27461 /* MakeTime */
27462 tmp_time = 0.0;
27463 tmp_time += dparts[DUK_DATE_IDX_HOUR] * ((duk_double_t) DUK_DATE_MSEC_HOUR);
27464 tmp_time += dparts[DUK_DATE_IDX_MINUTE] * ((duk_double_t) DUK_DATE_MSEC_MINUTE);
27465 tmp_time += dparts[DUK_DATE_IDX_SECOND] * ((duk_double_t) DUK_DATE_MSEC_SECOND);
27466 tmp_time += dparts[DUK_DATE_IDX_MILLISECOND];
27467
27468 /* MakeDay */
27469 tmp_day = duk__make_day(dparts[DUK_DATE_IDX_YEAR], dparts[DUK_DATE_IDX_MONTH], dparts[DUK_DATE_IDX_DAY]);
27470
27471 /* MakeDate */
27472 d = tmp_day * ((duk_double_t) DUK_DATE_MSEC_DAY) + tmp_time;
27473
27474 DUK_DDD(DUK_DDDPRINT("time=%lf day=%lf --> timeval=%lf",
27475 (double) tmp_time, (double) tmp_day, (double) d));
27476
27477 /* Optional UTC conversion. */
27478 if (flags & DUK_DATE_FLAG_LOCALTIME) {
27479 /* DUK_USE_DATE_GET_LOCAL_TZOFFSET() needs to be called with a
27480 * time value computed from UTC parts. At this point we only
27481 * have 'd' which is a time value computed from local parts, so
27482 * it is off by the UTC-to-local time offset which we don't know
27483 * yet. The current solution for computing the UTC-to-local
27484 * time offset is to iterate a few times and detect a fixed
27485 * point or a two-cycle loop (or a sanity iteration limit),
27486 * see test-bi-date-local-parts.js and test-bi-date-tzoffset-basic-fi.js.
27487 *
27488 * E5.1 Section 15.9.1.9:
27489 * UTC(t) = t - LocalTZA - DaylightSavingTA(t - LocalTZA)
27490 *
27491 * For NaN/inf, DUK_USE_DATE_GET_LOCAL_TZOFFSET() returns 0.
27492 */
27493
27494#if 0
27495 /* Old solution: don't iterate, incorrect */
27496 tzoff = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d);
27497 DUK_DDD(DUK_DDDPRINT("tzoffset w/o iteration, tzoff=%ld", (long) tzoff));
27498 d -= tzoff * 1000L;
27499 DUK_UNREF(tzoffprev1);
27500 DUK_UNREF(tzoffprev2);
27501#endif
27502
27503 /* Iteration solution */
27504 tzoff = 0;
27505 tzoffprev1 = 999999999L; /* invalid value which never matches */
27506 for (i = 0; i < DUK__LOCAL_TZOFFSET_MAXITER; i++) {
27507 tzoffprev2 = tzoffprev1;
27508 tzoffprev1 = tzoff;
27509 tzoff = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d - tzoff * 1000L);
27510 DUK_DDD(DUK_DDDPRINT("tzoffset iteration, i=%d, tzoff=%ld, tzoffprev1=%ld tzoffprev2=%ld",
27511 (int) i, (long) tzoff, (long) tzoffprev1, (long) tzoffprev2));
27512 if (tzoff == tzoffprev1) {
27513 DUK_DDD(DUK_DDDPRINT("tzoffset iteration finished, i=%d, tzoff=%ld, tzoffprev1=%ld, tzoffprev2=%ld",
27514 (int) i, (long) tzoff, (long) tzoffprev1, (long) tzoffprev2));
27515 break;
27516 } else if (tzoff == tzoffprev2) {
27517 /* Two value cycle, see e.g. test-bi-date-tzoffset-basic-fi.js.
27518 * In these cases, favor a higher tzoffset to get a consistent
27519 * result which is independent of iteration count. Not sure if
27520 * this is a generically correct solution.
27521 */
27522 DUK_DDD(DUK_DDDPRINT("tzoffset iteration two-value cycle, i=%d, tzoff=%ld, tzoffprev1=%ld, tzoffprev2=%ld",
27523 (int) i, (long) tzoff, (long) tzoffprev1, (long) tzoffprev2));
27524 if (tzoffprev1 > tzoff) {
27525 tzoff = tzoffprev1;
27526 }
27527 break;
27528 }
27529 }
27530 DUK_DDD(DUK_DDDPRINT("tzoffset iteration, tzoff=%ld", (long) tzoff));
27531 d -= tzoff * 1000L;
27532 }
27533
27534 /* TimeClip(), which also handles Infinity -> NaN conversion */
27535 d = duk__timeclip(d);
27536
27537 return d;
27538}
27539
27540/*
27541 * API oriented helpers
27542 */
27543
27544/* Push 'this' binding, check that it is a Date object; then push the
27545 * internal time value. At the end, stack is: [ ... this timeval ].
27546 * Returns the time value. Local time adjustment is done if requested.
27547 */
27548DUK_LOCAL duk_double_t duk__push_this_get_timeval_tzoffset(duk_context *ctx, duk_small_uint_t flags, duk_int_t *out_tzoffset) {
27549 duk_hthread *thr = (duk_hthread *) ctx;
27550 duk_hobject *h;
27551 duk_double_t d;
27552 duk_int_t tzoffset = 0;
27553
27554 duk_push_this(ctx);
27555 h = duk_get_hobject(ctx, -1); /* XXX: getter with class check, useful in built-ins */
27556 if (h == NULL || DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_DATE) {
27557 DUK_ERROR_TYPE(thr, "expected Date");
27558 }
27559
27560 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_VALUE);
27561 d = duk_to_number_m1(ctx);
27562 duk_pop(ctx);
27563
27564 if (DUK_ISNAN(d)) {
27565 if (flags & DUK_DATE_FLAG_NAN_TO_ZERO) {
27566 d = 0.0;
27567 }
27568 if (flags & DUK_DATE_FLAG_NAN_TO_RANGE_ERROR) {
27569 DUK_ERROR_RANGE(thr, "Invalid Date");
27570 }
27571 }
27572 /* if no NaN handling flag, may still be NaN here, but not Inf */
27573 DUK_ASSERT(!DUK_ISINF(d));
27574
27575 if (flags & DUK_DATE_FLAG_LOCALTIME) {
27576 /* Note: DST adjustment is determined using UTC time.
27577 * If 'd' is NaN, tzoffset will be 0.
27578 */
27579 tzoffset = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d); /* seconds */
27580 d += tzoffset * 1000L;
27581 }
27582 if (out_tzoffset) {
27583 *out_tzoffset = tzoffset;
27584 }
27585
27586 /* [ ... this ] */
27587 return d;
27588}
27589
27590DUK_LOCAL duk_double_t duk__push_this_get_timeval(duk_context *ctx, duk_small_uint_t flags) {
27591 return duk__push_this_get_timeval_tzoffset(ctx, flags, NULL);
27592}
27593
27594/* Set timeval to 'this' from dparts, push the new time value onto the
27595 * value stack and return 1 (caller can then tail call us). Expects
27596 * the value stack to contain 'this' on the stack top.
27597 */
27598DUK_LOCAL duk_ret_t duk__set_this_timeval_from_dparts(duk_context *ctx, duk_double_t *dparts, duk_small_uint_t flags) {
27599 duk_double_t d;
27600
27601 /* [ ... this ] */
27602
27603 d = duk_bi_date_get_timeval_from_dparts(dparts, flags);
27604 duk_push_number(ctx, d); /* -> [ ... this timeval_new ] */
27605 duk_dup_top(ctx); /* -> [ ... this timeval_new timeval_new ] */
27606 duk_put_prop_stridx_short(ctx, -3, DUK_STRIDX_INT_VALUE);
27607
27608 /* stack top: new time value, return 1 to allow tail calls */
27609 return 1;
27610}
27611
27612/* 'out_buf' must be at least DUK_BI_DATE_ISO8601_BUFSIZE long. */
27613DUK_LOCAL void duk__format_parts_iso8601(duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags, duk_uint8_t *out_buf) {
27614 char yearstr[8]; /* "-123456\0" */
27615 char tzstr[8]; /* "+11:22\0" */
27616 char sep = (flags & DUK_DATE_FLAG_SEP_T) ? DUK_ASC_UC_T : DUK_ASC_SPACE;
27617
27618 DUK_ASSERT(parts[DUK_DATE_IDX_MONTH] >= 1 && parts[DUK_DATE_IDX_MONTH] <= 12);
27619 DUK_ASSERT(parts[DUK_DATE_IDX_DAY] >= 1 && parts[DUK_DATE_IDX_DAY] <= 31);
27620 DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] >= -999999 && parts[DUK_DATE_IDX_YEAR] <= 999999);
27621
27622 /* Note: %06d for positive value, %07d for negative value to include
27623 * sign and 6 digits.
27624 */
27625 DUK_SNPRINTF(yearstr,
27626 sizeof(yearstr),
27627 (parts[DUK_DATE_IDX_YEAR] >= 0 && parts[DUK_DATE_IDX_YEAR] <= 9999) ? "%04ld" :
27628 ((parts[DUK_DATE_IDX_YEAR] >= 0) ? "+%06ld" : "%07ld"),
27629 (long) parts[DUK_DATE_IDX_YEAR]);
27630 yearstr[sizeof(yearstr) - 1] = (char) 0;
27631
27632 if (flags & DUK_DATE_FLAG_LOCALTIME) {
27633 /* tzoffset seconds are dropped; 16 bits suffice for
27634 * time offset in minutes
27635 */
27636 if (tzoffset >= 0) {
27637 duk_small_int_t tmp = tzoffset / 60;
27638 DUK_SNPRINTF(tzstr, sizeof(tzstr), "+%02d:%02d", (int) (tmp / 60), (int) (tmp % 60));
27639 } else {
27640 duk_small_int_t tmp = -tzoffset / 60;
27641 DUK_SNPRINTF(tzstr, sizeof(tzstr), "-%02d:%02d", (int) (tmp / 60), (int) (tmp % 60));
27642 }
27643 tzstr[sizeof(tzstr) - 1] = (char) 0;
27644 } else {
27645 tzstr[0] = DUK_ASC_UC_Z;
27646 tzstr[1] = (char) 0;
27647 }
27648
27649 /* Unlike year, the other parts fit into 16 bits so %d format
27650 * is portable.
27651 */
27652 if ((flags & DUK_DATE_FLAG_TOSTRING_DATE) && (flags & DUK_DATE_FLAG_TOSTRING_TIME)) {
27653 DUK_SPRINTF((char *) out_buf, "%s-%02d-%02d%c%02d:%02d:%02d.%03d%s",
27654 (const char *) yearstr, (int) parts[DUK_DATE_IDX_MONTH], (int) parts[DUK_DATE_IDX_DAY], (int) sep,
27655 (int) parts[DUK_DATE_IDX_HOUR], (int) parts[DUK_DATE_IDX_MINUTE],
27656 (int) parts[DUK_DATE_IDX_SECOND], (int) parts[DUK_DATE_IDX_MILLISECOND], (const char *) tzstr);
27657 } else if (flags & DUK_DATE_FLAG_TOSTRING_DATE) {
27658 DUK_SPRINTF((char *) out_buf, "%s-%02d-%02d",
27659 (const char *) yearstr, (int) parts[DUK_DATE_IDX_MONTH], (int) parts[DUK_DATE_IDX_DAY]);
27660 } else {
27661 DUK_ASSERT(flags & DUK_DATE_FLAG_TOSTRING_TIME);
27662 DUK_SPRINTF((char *) out_buf, "%02d:%02d:%02d.%03d%s",
27663 (int) parts[DUK_DATE_IDX_HOUR], (int) parts[DUK_DATE_IDX_MINUTE],
27664 (int) parts[DUK_DATE_IDX_SECOND], (int) parts[DUK_DATE_IDX_MILLISECOND],
27665 (const char *) tzstr);
27666 }
27667}
27668
27669/* Helper for string conversion calls: check 'this' binding, get the
27670 * internal time value, and format date and/or time in a few formats.
27671 * Return value allows tail calls.
27672 */
27673DUK_LOCAL duk_ret_t duk__to_string_helper(duk_context *ctx, duk_small_uint_t flags) {
27674 duk_double_t d;
27675 duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
27676 duk_int_t tzoffset; /* seconds, doesn't fit into 16 bits */
27677 duk_bool_t rc;
27678 duk_uint8_t buf[DUK_BI_DATE_ISO8601_BUFSIZE];
27679
27680 DUK_UNREF(rc); /* unreferenced with some options */
27681
27682 d = duk__push_this_get_timeval_tzoffset(ctx, flags, &tzoffset);
27683 if (DUK_ISNAN(d)) {
27684 duk_push_hstring_stridx(ctx, DUK_STRIDX_INVALID_DATE);
27685 return 1;
27686 }
27687 DUK_ASSERT(DUK_ISFINITE(d));
27688
27689 /* formatters always get one-based month/day-of-month */
27690 duk_bi_date_timeval_to_parts(d, parts, NULL, DUK_DATE_FLAG_ONEBASED);
27691 DUK_ASSERT(parts[DUK_DATE_IDX_MONTH] >= 1 && parts[DUK_DATE_IDX_MONTH] <= 12);
27692 DUK_ASSERT(parts[DUK_DATE_IDX_DAY] >= 1 && parts[DUK_DATE_IDX_DAY] <= 31);
27693
27694 if (flags & DUK_DATE_FLAG_TOSTRING_LOCALE) {
27695 /* try locale specific formatter; if it refuses to format the
27696 * string, fall back to an ISO 8601 formatted value in local
27697 * time.
27698 */
27699#if defined(DUK_USE_DATE_FORMAT_STRING)
27700 /* Contract, either:
27701 * - Push string to value stack and return 1
27702 * - Don't push anything and return 0
27703 */
27704
27705 rc = DUK_USE_DATE_FORMAT_STRING(ctx, parts, tzoffset, flags);
27706 if (rc != 0) {
27707 return 1;
27708 }
27709#else
27710 /* No locale specific formatter; this is OK, we fall back
27711 * to ISO 8601.
27712 */
27713#endif
27714 }
27715
27716 /* Different calling convention than above used because the helper
27717 * is shared.
27718 */
27719 duk__format_parts_iso8601(parts, tzoffset, flags, buf);
27720 duk_push_string(ctx, (const char *) buf);
27721 return 1;
27722}
27723
27724/* Helper for component getter calls: check 'this' binding, get the
27725 * internal time value, split it into parts (either as UTC time or
27726 * local time), push a specified component as a return value to the
27727 * value stack and return 1 (caller can then tail call us).
27728 */
27729DUK_LOCAL duk_ret_t duk__get_part_helper(duk_context *ctx, duk_small_uint_t flags_and_idx) {
27730 duk_double_t d;
27731 duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
27732 duk_small_uint_t idx_part = (duk_small_uint_t) (flags_and_idx >> DUK_DATE_FLAG_VALUE_SHIFT); /* unpack args */
27733
27734 DUK_ASSERT_DISABLE(idx_part >= 0); /* unsigned */
27735 DUK_ASSERT(idx_part < DUK_DATE_IDX_NUM_PARTS);
27736
27737 d = duk__push_this_get_timeval(ctx, flags_and_idx);
27738 if (DUK_ISNAN(d)) {
27739 duk_push_nan(ctx);
27740 return 1;
27741 }
27742 DUK_ASSERT(DUK_ISFINITE(d));
27743
27744 duk_bi_date_timeval_to_parts(d, parts, NULL, flags_and_idx); /* no need to mask idx portion */
27745
27746 /* Setter APIs detect special year numbers (0...99) and apply a +1900
27747 * only in certain cases. The legacy getYear() getter applies -1900
27748 * unconditionally.
27749 */
27750 duk_push_int(ctx, (flags_and_idx & DUK_DATE_FLAG_SUB1900) ? parts[idx_part] - 1900 : parts[idx_part]);
27751 return 1;
27752}
27753
27754/* Helper for component setter calls: check 'this' binding, get the
27755 * internal time value, split it into parts (either as UTC time or
27756 * local time), modify one or more components as specified, recompute
27757 * the time value, set it as the internal value. Finally, push the
27758 * new time value as a return value to the value stack and return 1
27759 * (caller can then tail call us).
27760 */
27761DUK_LOCAL duk_ret_t duk__set_part_helper(duk_context *ctx, duk_small_uint_t flags_and_maxnargs) {
27762 duk_double_t d;
27763 duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
27764 duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
27765 duk_idx_t nargs;
27766 duk_small_uint_t maxnargs = (duk_small_uint_t) (flags_and_maxnargs >> DUK_DATE_FLAG_VALUE_SHIFT); /* unpack args */
27767 duk_small_uint_t idx_first, idx;
27768 duk_small_uint_t i;
27769
27770 nargs = duk_get_top(ctx);
27771 d = duk__push_this_get_timeval(ctx, flags_and_maxnargs);
27772 DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
27773
27774 if (DUK_ISFINITE(d)) {
27775 duk_bi_date_timeval_to_parts(d, parts, dparts, flags_and_maxnargs);
27776 } else {
27777 /* NaN timevalue: we need to coerce the arguments, but
27778 * the resulting internal timestamp needs to remain NaN.
27779 * This works but is not pretty: parts and dparts will
27780 * be partially uninitialized, but we only write to them.
27781 */
27782 }
27783
27784 /*
27785 * Determining which datetime components to overwrite based on
27786 * stack arguments is a bit complicated, but important to factor
27787 * out from setters themselves for compactness.
27788 *
27789 * If DUK_DATE_FLAG_TIMESETTER, maxnargs indicates setter type:
27790 *
27791 * 1 -> millisecond
27792 * 2 -> second, [millisecond]
27793 * 3 -> minute, [second], [millisecond]
27794 * 4 -> hour, [minute], [second], [millisecond]
27795 *
27796 * Else:
27797 *
27798 * 1 -> date
27799 * 2 -> month, [date]
27800 * 3 -> year, [month], [date]
27801 *
27802 * By comparing nargs and maxnargs (and flags) we know which
27803 * components to override. We rely on part index ordering.
27804 */
27805
27806 if (flags_and_maxnargs & DUK_DATE_FLAG_TIMESETTER) {
27807 DUK_ASSERT(maxnargs >= 1 && maxnargs <= 4);
27808 idx_first = DUK_DATE_IDX_MILLISECOND - (maxnargs - 1);
27809 } else {
27810 DUK_ASSERT(maxnargs >= 1 && maxnargs <= 3);
27811 idx_first = DUK_DATE_IDX_DAY - (maxnargs - 1);
27812 }
27813 DUK_ASSERT_DISABLE(idx_first >= 0); /* unsigned */
27814 DUK_ASSERT(idx_first < DUK_DATE_IDX_NUM_PARTS);
27815
27816 for (i = 0; i < maxnargs; i++) {
27817 if ((duk_idx_t) i >= nargs) {
27818 /* no argument given -> leave components untouched */
27819 break;
27820 }
27821 idx = idx_first + i;
27822 DUK_ASSERT_DISABLE(idx >= 0); /* unsigned */
27823 DUK_ASSERT(idx < DUK_DATE_IDX_NUM_PARTS);
27824
27825 if (idx == DUK_DATE_IDX_YEAR && (flags_and_maxnargs & DUK_DATE_FLAG_YEAR_FIXUP)) {
27826 duk__twodigit_year_fixup(ctx, (duk_idx_t) i);
27827 }
27828
27829 dparts[idx] = duk_to_number(ctx, i);
27830
27831 if (idx == DUK_DATE_IDX_DAY) {
27832 /* Day-of-month is one-based in the API, but zero-based
27833 * internally, so fix here. Note that month is zero-based
27834 * both in the API and internally.
27835 */
27836 /* SCANBUILD: complains about use of uninitialized values.
27837 * The complaint is correct, but operating in undefined
27838 * values here is intentional in some cases and the caller
27839 * ignores the results.
27840 */
27841 dparts[idx] -= 1.0;
27842 }
27843 }
27844
27845 /* Leaves new timevalue on stack top and returns 1, which is correct
27846 * for part setters.
27847 */
27848 if (DUK_ISFINITE(d)) {
27849 return duk__set_this_timeval_from_dparts(ctx, dparts, flags_and_maxnargs);
27850 } else {
27851 /* Internal timevalue is already NaN, so don't touch it. */
27852 duk_push_nan(ctx);
27853 return 1;
27854 }
27855}
27856
27857/* Apply ToNumber() to specified index; if ToInteger(val) in [0,99], add
27858 * 1900 and replace value at idx_val.
27859 */
27860DUK_LOCAL void duk__twodigit_year_fixup(duk_context *ctx, duk_idx_t idx_val) {
27861 duk_double_t d;
27862
27863 /* XXX: idx_val would fit into 16 bits, but using duk_small_uint_t
27864 * might not generate better code due to casting.
27865 */
27866
27867 /* E5 Sections 15.9.3.1, B.2.4, B.2.5 */
27868 duk_to_number(ctx, idx_val);
27869 if (duk_is_nan(ctx, idx_val)) {
27870 return;
27871 }
27872 duk_dup(ctx, idx_val);
27873 duk_to_int(ctx, -1);
27874 d = duk_get_number(ctx, -1); /* get as double to handle huge numbers correctly */
27875 if (d >= 0.0 && d <= 99.0) {
27876 d += 1900.0;
27877 duk_push_number(ctx, d);
27878 duk_replace(ctx, idx_val);
27879 }
27880 duk_pop(ctx);
27881}
27882
27883/* Set datetime parts from stack arguments, defaulting any missing values.
27884 * Day-of-week is not set; it is not required when setting the time value.
27885 */
27886DUK_LOCAL void duk__set_parts_from_args(duk_context *ctx, duk_double_t *dparts, duk_idx_t nargs) {
27887 duk_double_t d;
27888 duk_small_uint_t i;
27889 duk_small_uint_t idx;
27890
27891 /* Causes a ToNumber() coercion, but doesn't break coercion order since
27892 * year is coerced first anyway.
27893 */
27894 duk__twodigit_year_fixup(ctx, 0);
27895
27896 /* There are at most 7 args, but we use 8 here so that also
27897 * DUK_DATE_IDX_WEEKDAY gets initialized (to zero) to avoid the potential
27898 * for any Valgrind gripes later.
27899 */
27900 for (i = 0; i < 8; i++) {
27901 /* Note: rely on index ordering */
27902 idx = DUK_DATE_IDX_YEAR + i;
27903 if ((duk_idx_t) i < nargs) {
27904 d = duk_to_number(ctx, (duk_idx_t) i);
27905 if (idx == DUK_DATE_IDX_DAY) {
27906 /* Convert day from one-based to zero-based (internal). This may
27907 * cause the day part to be negative, which is OK.
27908 */
27909 d -= 1.0;
27910 }
27911 } else {
27912 /* All components default to 0 except day-of-month which defaults
27913 * to 1. However, because our internal day-of-month is zero-based,
27914 * it also defaults to zero here.
27915 */
27916 d = 0.0;
27917 }
27918 dparts[idx] = d;
27919 }
27920
27921 DUK_DDD(DUK_DDDPRINT("parts from args -> %lf %lf %lf %lf %lf %lf %lf %lf",
27922 (double) dparts[0], (double) dparts[1],
27923 (double) dparts[2], (double) dparts[3],
27924 (double) dparts[4], (double) dparts[5],
27925 (double) dparts[6], (double) dparts[7]));
27926}
27927
27928/*
27929 * Indirect magic value lookup for Date methods.
27930 *
27931 * Date methods don't put their control flags into the function magic value
27932 * because they wouldn't fit into a LIGHTFUNC's magic field. Instead, the
27933 * magic value is set to an index pointing to the array of control flags
27934 * below.
27935 *
27936 * This must be kept in strict sync with genbuiltins.py!
27937 */
27938
27939static duk_uint16_t duk__date_magics[] = {
27940 /* 0: toString */
27941 DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_LOCALTIME,
27942
27943 /* 1: toDateString */
27944 DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_LOCALTIME,
27945
27946 /* 2: toTimeString */
27947 DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_LOCALTIME,
27948
27949 /* 3: toLocaleString */
27950 DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_TOSTRING_LOCALE + DUK_DATE_FLAG_LOCALTIME,
27951
27952 /* 4: toLocaleDateString */
27953 DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_LOCALE + DUK_DATE_FLAG_LOCALTIME,
27954
27955 /* 5: toLocaleTimeString */
27956 DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_TOSTRING_LOCALE + DUK_DATE_FLAG_LOCALTIME,
27957
27958 /* 6: toUTCString */
27959 DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME,
27960
27961 /* 7: toISOString */
27962 DUK_DATE_FLAG_TOSTRING_DATE + DUK_DATE_FLAG_TOSTRING_TIME + DUK_DATE_FLAG_NAN_TO_RANGE_ERROR + DUK_DATE_FLAG_SEP_T,
27963
27964 /* 8: getFullYear */
27965 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_YEAR << DUK_DATE_FLAG_VALUE_SHIFT),
27966
27967 /* 9: getUTCFullYear */
27968 0 + (DUK_DATE_IDX_YEAR << DUK_DATE_FLAG_VALUE_SHIFT),
27969
27970 /* 10: getMonth */
27971 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_MONTH << DUK_DATE_FLAG_VALUE_SHIFT),
27972
27973 /* 11: getUTCMonth */
27974 0 + (DUK_DATE_IDX_MONTH << DUK_DATE_FLAG_VALUE_SHIFT),
27975
27976 /* 12: getDate */
27977 DUK_DATE_FLAG_ONEBASED + DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_DAY << DUK_DATE_FLAG_VALUE_SHIFT),
27978
27979 /* 13: getUTCDate */
27980 DUK_DATE_FLAG_ONEBASED + (DUK_DATE_IDX_DAY << DUK_DATE_FLAG_VALUE_SHIFT),
27981
27982 /* 14: getDay */
27983 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_WEEKDAY << DUK_DATE_FLAG_VALUE_SHIFT),
27984
27985 /* 15: getUTCDay */
27986 0 + (DUK_DATE_IDX_WEEKDAY << DUK_DATE_FLAG_VALUE_SHIFT),
27987
27988 /* 16: getHours */
27989 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_HOUR << DUK_DATE_FLAG_VALUE_SHIFT),
27990
27991 /* 17: getUTCHours */
27992 0 + (DUK_DATE_IDX_HOUR << DUK_DATE_FLAG_VALUE_SHIFT),
27993
27994 /* 18: getMinutes */
27995 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_MINUTE << DUK_DATE_FLAG_VALUE_SHIFT),
27996
27997 /* 19: getUTCMinutes */
27998 0 + (DUK_DATE_IDX_MINUTE << DUK_DATE_FLAG_VALUE_SHIFT),
27999
28000 /* 20: getSeconds */
28001 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_SECOND << DUK_DATE_FLAG_VALUE_SHIFT),
28002
28003 /* 21: getUTCSeconds */
28004 0 + (DUK_DATE_IDX_SECOND << DUK_DATE_FLAG_VALUE_SHIFT),
28005
28006 /* 22: getMilliseconds */
28007 DUK_DATE_FLAG_LOCALTIME + (DUK_DATE_IDX_MILLISECOND << DUK_DATE_FLAG_VALUE_SHIFT),
28008
28009 /* 23: getUTCMilliseconds */
28010 0 + (DUK_DATE_IDX_MILLISECOND << DUK_DATE_FLAG_VALUE_SHIFT),
28011
28012 /* 24: setMilliseconds */
28013 DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (1 << DUK_DATE_FLAG_VALUE_SHIFT),
28014
28015 /* 25: setUTCMilliseconds */
28016 DUK_DATE_FLAG_TIMESETTER + (1 << DUK_DATE_FLAG_VALUE_SHIFT),
28017
28018 /* 26: setSeconds */
28019 DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (2 << DUK_DATE_FLAG_VALUE_SHIFT),
28020
28021 /* 27: setUTCSeconds */
28022 DUK_DATE_FLAG_TIMESETTER + (2 << DUK_DATE_FLAG_VALUE_SHIFT),
28023
28024 /* 28: setMinutes */
28025 DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
28026
28027 /* 29: setUTCMinutes */
28028 DUK_DATE_FLAG_TIMESETTER + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
28029
28030 /* 30: setHours */
28031 DUK_DATE_FLAG_TIMESETTER + DUK_DATE_FLAG_LOCALTIME + (4 << DUK_DATE_FLAG_VALUE_SHIFT),
28032
28033 /* 31: setUTCHours */
28034 DUK_DATE_FLAG_TIMESETTER + (4 << DUK_DATE_FLAG_VALUE_SHIFT),
28035
28036 /* 32: setDate */
28037 DUK_DATE_FLAG_LOCALTIME + (1 << DUK_DATE_FLAG_VALUE_SHIFT),
28038
28039 /* 33: setUTCDate */
28040 0 + (1 << DUK_DATE_FLAG_VALUE_SHIFT),
28041
28042 /* 34: setMonth */
28043 DUK_DATE_FLAG_LOCALTIME + (2 << DUK_DATE_FLAG_VALUE_SHIFT),
28044
28045 /* 35: setUTCMonth */
28046 0 + (2 << DUK_DATE_FLAG_VALUE_SHIFT),
28047
28048 /* 36: setFullYear */
28049 DUK_DATE_FLAG_NAN_TO_ZERO + DUK_DATE_FLAG_LOCALTIME + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
28050
28051 /* 37: setUTCFullYear */
28052 DUK_DATE_FLAG_NAN_TO_ZERO + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
28053
28054 /* 38: getYear */
28055 DUK_DATE_FLAG_LOCALTIME + DUK_DATE_FLAG_SUB1900 + (DUK_DATE_IDX_YEAR << DUK_DATE_FLAG_VALUE_SHIFT),
28056
28057 /* 39: setYear */
28058 DUK_DATE_FLAG_NAN_TO_ZERO + DUK_DATE_FLAG_YEAR_FIXUP + (3 << DUK_DATE_FLAG_VALUE_SHIFT),
28059};
28060
28061DUK_LOCAL duk_small_uint_t duk__date_get_indirect_magic(duk_context *ctx) {
28062 duk_small_int_t magicidx = (duk_small_uint_t) duk_get_current_magic(ctx);
28063 DUK_ASSERT(magicidx >= 0 && magicidx < (duk_small_int_t) (sizeof(duk__date_magics) / sizeof(duk_uint16_t)));
28064 return (duk_small_uint_t) duk__date_magics[magicidx];
28065}
28066
28067#if defined(DUK_USE_DATE_BUILTIN)
28068/*
28069 * Constructor calls
28070 */
28071
28072DUK_INTERNAL duk_ret_t duk_bi_date_constructor(duk_context *ctx) {
28073 duk_idx_t nargs = duk_get_top(ctx);
28074 duk_bool_t is_cons = duk_is_constructor_call(ctx);
28075 duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
28076 duk_double_t d;
28077
28078 DUK_DDD(DUK_DDDPRINT("Date constructor, nargs=%ld, is_cons=%ld", (long) nargs, (long) is_cons));
28079
28080 (void) duk_push_object_helper(ctx,
28081 DUK_HOBJECT_FLAG_EXTENSIBLE |
28082 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DATE),
28083 DUK_BIDX_DATE_PROTOTYPE);
28084
28085 /* Unlike most built-ins, the internal [[PrimitiveValue]] of a Date
28086 * is mutable.
28087 */
28088
28089 if (nargs == 0 || !is_cons) {
28090 d = duk__timeclip(DUK_USE_DATE_GET_NOW(ctx));
28091 duk_push_number(ctx, d);
28092 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
28093 if (!is_cons) {
28094 /* called as a normal function: return new Date().toString() */
28095 duk_to_string(ctx, -1);
28096 }
28097 return 1;
28098 } else if (nargs == 1) {
28099 const char *str;
28100 duk_to_primitive(ctx, 0, DUK_HINT_NONE);
28101 str = duk_get_string_notsymbol(ctx, 0);
28102 if (str) {
28103 duk__parse_string(ctx, str);
28104 duk_replace(ctx, 0); /* may be NaN */
28105 }
28106 d = duk__timeclip(duk_to_number(ctx, 0)); /* symbols fail here */
28107 duk_push_number(ctx, d);
28108 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_W);
28109 return 1;
28110 }
28111
28112 duk__set_parts_from_args(ctx, dparts, nargs);
28113
28114 /* Parts are in local time, convert when setting. */
28115
28116 (void) duk__set_this_timeval_from_dparts(ctx, dparts, DUK_DATE_FLAG_LOCALTIME /*flags*/); /* -> [ ... this timeval ] */
28117 duk_pop(ctx); /* -> [ ... this ] */
28118 return 1;
28119}
28120
28121DUK_INTERNAL duk_ret_t duk_bi_date_constructor_parse(duk_context *ctx) {
28122 return duk__parse_string(ctx, duk_to_string(ctx, 0));
28123}
28124
28125DUK_INTERNAL duk_ret_t duk_bi_date_constructor_utc(duk_context *ctx) {
28126 duk_idx_t nargs = duk_get_top(ctx);
28127 duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
28128 duk_double_t d;
28129
28130 /* Behavior for nargs < 2 is implementation dependent: currently we'll
28131 * set a NaN time value (matching V8 behavior) in this case.
28132 */
28133
28134 if (nargs < 2) {
28135 duk_push_nan(ctx);
28136 } else {
28137 duk__set_parts_from_args(ctx, dparts, nargs);
28138 d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
28139 duk_push_number(ctx, d);
28140 }
28141 return 1;
28142}
28143
28144DUK_INTERNAL duk_ret_t duk_bi_date_constructor_now(duk_context *ctx) {
28145 duk_double_t d;
28146
28147 d = DUK_USE_DATE_GET_NOW(ctx);
28148 DUK_ASSERT(duk__timeclip(d) == d); /* TimeClip() should never be necessary */
28149 duk_push_number(ctx, d);
28150 return 1;
28151}
28152
28153/*
28154 * String/JSON conversions
28155 *
28156 * Human readable conversions are now basically ISO 8601 with a space
28157 * (instead of 'T') as the date/time separator. This is a good baseline
28158 * and is platform independent.
28159 *
28160 * A shared native helper to provide many conversions. Magic value contains
28161 * a set of flags. The helper provides:
28162 *
28163 * toString()
28164 * toDateString()
28165 * toTimeString()
28166 * toLocaleString()
28167 * toLocaleDateString()
28168 * toLocaleTimeString()
28169 * toUTCString()
28170 * toISOString()
28171 *
28172 * Notes:
28173 *
28174 * - Date.prototype.toGMTString() and Date.prototype.toUTCString() are
28175 * required to be the same Ecmascript function object (!), so it is
28176 * omitted from here.
28177 *
28178 * - Date.prototype.toUTCString(): E5.1 specification does not require a
28179 * specific format, but result should be human readable. The
28180 * specification suggests using ISO 8601 format with a space (instead
28181 * of 'T') separator if a more human readable format is not available.
28182 *
28183 * - Date.prototype.toISOString(): unlike other conversion functions,
28184 * toISOString() requires a RangeError for invalid date values.
28185 */
28186
28187DUK_INTERNAL duk_ret_t duk_bi_date_prototype_tostring_shared(duk_context *ctx) {
28188 duk_small_uint_t flags = duk__date_get_indirect_magic(ctx);
28189 return duk__to_string_helper(ctx, flags);
28190}
28191
28192DUK_INTERNAL duk_ret_t duk_bi_date_prototype_value_of(duk_context *ctx) {
28193 /* This native function is also used for Date.prototype.getTime()
28194 * as their behavior is identical.
28195 */
28196
28197 duk_double_t d = duk__push_this_get_timeval(ctx, 0 /*flags*/); /* -> [ this ] */
28198 DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
28199 duk_push_number(ctx, d);
28200 return 1;
28201}
28202
28203DUK_INTERNAL duk_ret_t duk_bi_date_prototype_to_json(duk_context *ctx) {
28204 /* Note: toJSON() is a generic function which works even if 'this'
28205 * is not a Date. The sole argument is ignored.
28206 */
28207
28208 duk_push_this(ctx);
28209 duk_to_object(ctx, -1);
28210
28211 duk_dup_top(ctx);
28212 duk_to_primitive(ctx, -1, DUK_HINT_NUMBER);
28213 if (duk_is_number(ctx, -1)) {
28214 duk_double_t d = duk_get_number(ctx, -1);
28215 if (!DUK_ISFINITE(d)) {
28216 duk_push_null(ctx);
28217 return 1;
28218 }
28219 }
28220 duk_pop(ctx);
28221
28222 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_TO_ISO_STRING);
28223 duk_dup_m2(ctx); /* -> [ O toIsoString O ] */
28224 duk_call_method(ctx, 0);
28225 return 1;
28226}
28227
28228/*
28229 * Getters.
28230 *
28231 * Implementing getters is quite easy. The internal time value is either
28232 * NaN, or represents milliseconds (without fractions) from Jan 1, 1970.
28233 * The internal time value can be converted to integer parts, and each
28234 * part will be normalized and will fit into a 32-bit signed integer.
28235 *
28236 * A shared native helper to provide all getters. Magic value contains
28237 * a set of flags and also packs the date component index argument. The
28238 * helper provides:
28239 *
28240 * getFullYear()
28241 * getUTCFullYear()
28242 * getMonth()
28243 * getUTCMonth()
28244 * getDate()
28245 * getUTCDate()
28246 * getDay()
28247 * getUTCDay()
28248 * getHours()
28249 * getUTCHours()
28250 * getMinutes()
28251 * getUTCMinutes()
28252 * getSeconds()
28253 * getUTCSeconds()
28254 * getMilliseconds()
28255 * getUTCMilliseconds()
28256 * getYear()
28257 *
28258 * Notes:
28259 *
28260 * - Date.prototype.getDate(): 'date' means day-of-month, and is
28261 * zero-based in internal calculations but public API expects it to
28262 * be one-based.
28263 *
28264 * - Date.prototype.getTime() and Date.prototype.valueOf() have identical
28265 * behavior. They have separate function objects, but share the same C
28266 * function (duk_bi_date_prototype_value_of).
28267 */
28268
28269DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_shared(duk_context *ctx) {
28270 duk_small_uint_t flags_and_idx = duk__date_get_indirect_magic(ctx);
28271 return duk__get_part_helper(ctx, flags_and_idx);
28272}
28273
28274DUK_INTERNAL duk_ret_t duk_bi_date_prototype_get_timezone_offset(duk_context *ctx) {
28275 /*
28276 * Return (t - LocalTime(t)) in minutes:
28277 *
28278 * t - LocalTime(t) = t - (t + LocalTZA + DaylightSavingTA(t))
28279 * = -(LocalTZA + DaylightSavingTA(t))
28280 *
28281 * where DaylightSavingTA() is checked for time 't'.
28282 *
28283 * Note that the sign of the result is opposite to common usage,
28284 * e.g. for EE(S)T which normally is +2h or +3h from UTC, this
28285 * function returns -120 or -180.
28286 *
28287 */
28288
28289 duk_double_t d;
28290 duk_int_t tzoffset;
28291
28292 /* Note: DST adjustment is determined using UTC time. */
28293 d = duk__push_this_get_timeval(ctx, 0 /*flags*/);
28294 DUK_ASSERT(DUK_ISFINITE(d) || DUK_ISNAN(d));
28295 if (DUK_ISNAN(d)) {
28296 duk_push_nan(ctx);
28297 } else {
28298 DUK_ASSERT(DUK_ISFINITE(d));
28299 tzoffset = DUK_USE_DATE_GET_LOCAL_TZOFFSET(d);
28300 duk_push_int(ctx, -tzoffset / 60);
28301 }
28302 return 1;
28303}
28304
28305/*
28306 * Setters.
28307 *
28308 * Setters are a bit more complicated than getters. Component setters
28309 * break down the current time value into its (normalized) component
28310 * parts, replace one or more components with -unnormalized- new values,
28311 * and the components are then converted back into a time value. As an
28312 * example of using unnormalized values:
28313 *
28314 * var d = new Date(1234567890);
28315 *
28316 * is equivalent to:
28317 *
28318 * var d = new Date(0);
28319 * d.setUTCMilliseconds(1234567890);
28320 *
28321 * A shared native helper to provide almost all setters. Magic value
28322 * contains a set of flags and also packs the "maxnargs" argument. The
28323 * helper provides:
28324 *
28325 * setMilliseconds()
28326 * setUTCMilliseconds()
28327 * setSeconds()
28328 * setUTCSeconds()
28329 * setMinutes()
28330 * setUTCMinutes()
28331 * setHours()
28332 * setUTCHours()
28333 * setDate()
28334 * setUTCDate()
28335 * setMonth()
28336 * setUTCMonth()
28337 * setFullYear()
28338 * setUTCFullYear()
28339 * setYear()
28340 *
28341 * Notes:
28342 *
28343 * - Date.prototype.setYear() (Section B addition): special year check
28344 * is omitted. NaN / Infinity will just flow through and ultimately
28345 * result in a NaN internal time value.
28346 *
28347 * - Date.prototype.setYear() does not have optional arguments for
28348 * setting month and day-in-month (like setFullYear()), but we indicate
28349 * 'maxnargs' to be 3 to get the year written to the correct component
28350 * index in duk__set_part_helper(). The function has nargs == 1, so only
28351 * the year will be set regardless of actual argument count.
28352 */
28353
28354DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_shared(duk_context *ctx) {
28355 duk_small_uint_t flags_and_maxnargs = duk__date_get_indirect_magic(ctx);
28356 return duk__set_part_helper(ctx, flags_and_maxnargs);
28357}
28358
28359DUK_INTERNAL duk_ret_t duk_bi_date_prototype_set_time(duk_context *ctx) {
28360 duk_double_t d;
28361
28362 (void) duk__push_this_get_timeval(ctx, 0 /*flags*/); /* -> [ timeval this ] */
28363 d = duk__timeclip(duk_to_number(ctx, 0));
28364 duk_push_number(ctx, d);
28365 duk_dup_top(ctx);
28366 duk_put_prop_stridx_short(ctx, -3, DUK_STRIDX_INT_VALUE); /* -> [ timeval this timeval ] */
28367
28368 return 1;
28369}
28370
28371#endif /* DUK_USE_DATE_BUILTIN */
28372
28373/* automatic undefs */
28374#undef DUK__CF_ACCEPT
28375#undef DUK__CF_ACCEPT_NUL
28376#undef DUK__CF_NEG
28377#undef DUK__DPRINT_DPARTS
28378#undef DUK__DPRINT_PARTS
28379#undef DUK__DPRINT_PARTS_AND_DPARTS
28380#undef DUK__LOCAL_TZOFFSET_MAXITER
28381#undef DUK__NUM_ISO8601_PARSER_PARTS
28382#undef DUK__PACK_RULE
28383#undef DUK__PI_DAY
28384#undef DUK__PI_HOUR
28385#undef DUK__PI_MILLISECOND
28386#undef DUK__PI_MINUTE
28387#undef DUK__PI_MONTH
28388#undef DUK__PI_SECOND
28389#undef DUK__PI_TZHOUR
28390#undef DUK__PI_TZMINUTE
28391#undef DUK__PI_YEAR
28392#undef DUK__PM_DAY
28393#undef DUK__PM_HOUR
28394#undef DUK__PM_MILLISECOND
28395#undef DUK__PM_MINUTE
28396#undef DUK__PM_MONTH
28397#undef DUK__PM_SECOND
28398#undef DUK__PM_TZHOUR
28399#undef DUK__PM_TZMINUTE
28400#undef DUK__PM_YEAR
28401#undef DUK__RULE_MASK_PART_SEP
28402#undef DUK__SI_COLON
28403#undef DUK__SI_MINUS
28404#undef DUK__SI_NUL
28405#undef DUK__SI_PERIOD
28406#undef DUK__SI_PLUS
28407#undef DUK__SI_SPACE
28408#undef DUK__SI_T
28409#undef DUK__SI_Z
28410#undef DUK__SM_COLON
28411#undef DUK__SM_MINUS
28412#undef DUK__SM_NUL
28413#undef DUK__SM_PERIOD
28414#undef DUK__SM_PLUS
28415#undef DUK__SM_SPACE
28416#undef DUK__SM_T
28417#undef DUK__SM_Z
28418#undef DUK__UNPACK_RULE
28419#undef DUK__WEEKDAY_MOD_ADDER
28420#undef DUK__YEAR
28421/*
28422 * Unix-like Date providers
28423 *
28424 * Generally useful Unix / POSIX / ANSI Date providers.
28425 */
28426
28427/* #include duk_internal.h -> already included */
28428
28429/* The necessary #includes are in place in duk_config.h. */
28430
28431/* Buffer sizes for some UNIX calls. Larger than strictly necessary
28432 * to avoid Valgrind errors.
28433 */
28434#define DUK__STRPTIME_BUF_SIZE 64
28435#define DUK__STRFTIME_BUF_SIZE 64
28436
28437#if defined(DUK_USE_DATE_NOW_GETTIMEOFDAY)
28438/* Get current Ecmascript time (= UNIX/Posix time, but in milliseconds). */
28439DUK_INTERNAL duk_double_t duk_bi_date_get_now_gettimeofday(duk_context *ctx) {
28440 duk_hthread *thr = (duk_hthread *) ctx;
28441 struct timeval tv;
28442 duk_double_t d;
28443
28444 if (gettimeofday(&tv, NULL) != 0) {
28445 DUK_ERROR_INTERNAL(thr);
28446 }
28447
28448 d = ((duk_double_t) tv.tv_sec) * 1000.0 +
28449 ((duk_double_t) (tv.tv_usec / 1000));
28450 DUK_ASSERT(DUK_FLOOR(d) == d); /* no fractions */
28451
28452 return d;
28453}
28454#endif /* DUK_USE_DATE_NOW_GETTIMEOFDAY */
28455
28456#if defined(DUK_USE_DATE_NOW_TIME)
28457/* Not a very good provider: only full seconds are available. */
28458DUK_INTERNAL duk_double_t duk_bi_date_get_now_time(duk_context *ctx) {
28459 time_t t;
28460
28461 DUK_UNREF(ctx);
28462 t = time(NULL);
28463 return ((duk_double_t) t) * 1000.0;
28464}
28465#endif /* DUK_USE_DATE_NOW_TIME */
28466
28467#if defined(DUK_USE_DATE_TZO_GMTIME) || defined(DUK_USE_DATE_TZO_GMTIME_R) || defined(DUK_USE_DATE_TZO_GMTIME_S)
28468/* Get local time offset (in seconds) for a certain (UTC) instant 'd'. */
28469DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_gmtime(duk_double_t d) {
28470 time_t t, t1, t2;
28471 duk_int_t parts[DUK_DATE_IDX_NUM_PARTS];
28472 duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS];
28473 struct tm tms[2];
28474#if defined(DUK_USE_DATE_TZO_GMTIME)
28475 struct tm *tm_ptr;
28476#endif
28477
28478 /* For NaN/inf, the return value doesn't matter. */
28479 if (!DUK_ISFINITE(d)) {
28480 return 0;
28481 }
28482
28483 /* If not within Ecmascript range, some integer time calculations
28484 * won't work correctly (and some asserts will fail), so bail out
28485 * if so. This fixes test-bug-date-insane-setyear.js. There is
28486 * a +/- 24h leeway in this range check to avoid a test262 corner
28487 * case documented in test-bug-date-timeval-edges.js.
28488 */
28489 if (!duk_bi_date_timeval_in_leeway_range(d)) {
28490 DUK_DD(DUK_DDPRINT("timeval not within valid range, skip tzoffset computation to avoid integer overflows"));
28491 return 0;
28492 }
28493
28494 /*
28495 * This is a bit tricky to implement portably. The result depends
28496 * on the timestamp (specifically, DST depends on the timestamp).
28497 * If e.g. UNIX APIs are used, they'll have portability issues with
28498 * very small and very large years.
28499 *
28500 * Current approach:
28501 *
28502 * - Stay within portable UNIX limits by using equivalent year mapping.
28503 * Avoid year 1970 and 2038 as some conversions start to fail, at
28504 * least on some platforms. Avoiding 1970 means that there are
28505 * currently DST discrepancies for 1970.
28506 *
28507 * - Create a UTC and local time breakdowns from 't'. Then create
28508 * a time_t using gmtime() and localtime() and compute the time
28509 * difference between the two.
28510 *
28511 * Equivalent year mapping (E5 Section 15.9.1.8):
28512 *
28513 * If the host environment provides functionality for determining
28514 * daylight saving time, the implementation of ECMAScript is free
28515 * to map the year in question to an equivalent year (same
28516 * leap-year-ness and same starting week day for the year) for which
28517 * the host environment provides daylight saving time information.
28518 * The only restriction is that all equivalent years should produce
28519 * the same result.
28520 *
28521 * This approach is quite reasonable but not entirely correct, e.g.
28522 * the specification also states (E5 Section 15.9.1.8):
28523 *
28524 * The implementation of ECMAScript should not try to determine
28525 * whether the exact time was subject to daylight saving time, but
28526 * just whether daylight saving time would have been in effect if
28527 * the _current daylight saving time algorithm_ had been used at the
28528 * time. This avoids complications such as taking into account the
28529 * years that the locale observed daylight saving time year round.
28530 *
28531 * Since we rely on the platform APIs for conversions between local
28532 * time and UTC, we can't guarantee the above. Rather, if the platform
28533 * has historical DST rules they will be applied. This seems to be the
28534 * general preferred direction in Ecmascript standardization (or at least
28535 * implementations) anyway, and even the equivalent year mapping should
28536 * be disabled if the platform is known to handle DST properly for the
28537 * full Ecmascript range.
28538 *
28539 * The following has useful discussion and links:
28540 *
28541 * https://bugzilla.mozilla.org/show_bug.cgi?id=351066
28542 */
28543
28544 duk_bi_date_timeval_to_parts(d, parts, dparts, DUK_DATE_FLAG_EQUIVYEAR /*flags*/);
28545 DUK_ASSERT(parts[DUK_DATE_IDX_YEAR] >= 1970 && parts[DUK_DATE_IDX_YEAR] <= 2038);
28546
28547 d = duk_bi_date_get_timeval_from_dparts(dparts, 0 /*flags*/);
28548 DUK_ASSERT(d >= 0 && d < 2147483648.0 * 1000.0); /* unsigned 31-bit range */
28549 t = (time_t) (d / 1000.0);
28550 DUK_DDD(DUK_DDDPRINT("timeval: %lf -> time_t %ld", (double) d, (long) t));
28551
28552 DUK_MEMZERO((void *) tms, sizeof(struct tm) * 2);
28553
28554#if defined(DUK_USE_DATE_TZO_GMTIME_R)
28555 (void) gmtime_r(&t, &tms[0]);
28556 (void) localtime_r(&t, &tms[1]);
28557#elif defined(DUK_USE_DATE_TZO_GMTIME_S)
28558 (void) gmtime_s(&t, &tms[0]);
28559 (void) localtime_s(&t, &tms[1]);
28560#elif defined(DUK_USE_DATE_TZO_GMTIME)
28561 tm_ptr = gmtime(&t);
28562 DUK_MEMCPY((void *) &tms[0], tm_ptr, sizeof(struct tm));
28563 tm_ptr = localtime(&t);
28564 DUK_MEMCPY((void *) &tms[1], tm_ptr, sizeof(struct tm));
28565#else
28566#error internal error
28567#endif
28568 DUK_DDD(DUK_DDDPRINT("gmtime result: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld,"
28569 "wday:%ld,yday:%ld,isdst:%ld}",
28570 (long) tms[0].tm_sec, (long) tms[0].tm_min, (long) tms[0].tm_hour,
28571 (long) tms[0].tm_mday, (long) tms[0].tm_mon, (long) tms[0].tm_year,
28572 (long) tms[0].tm_wday, (long) tms[0].tm_yday, (long) tms[0].tm_isdst));
28573 DUK_DDD(DUK_DDDPRINT("localtime result: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld,"
28574 "wday:%ld,yday:%ld,isdst:%ld}",
28575 (long) tms[1].tm_sec, (long) tms[1].tm_min, (long) tms[1].tm_hour,
28576 (long) tms[1].tm_mday, (long) tms[1].tm_mon, (long) tms[1].tm_year,
28577 (long) tms[1].tm_wday, (long) tms[1].tm_yday, (long) tms[1].tm_isdst));
28578
28579 /* tm_isdst is both an input and an output to mktime(), use 0 to
28580 * avoid DST handling in mktime():
28581 * - https://github.com/svaarala/duktape/issues/406
28582 * - http://stackoverflow.com/questions/8558919/mktime-and-tm-isdst
28583 */
28584 tms[0].tm_isdst = 0;
28585 tms[1].tm_isdst = 0;
28586 t1 = mktime(&tms[0]); /* UTC */
28587 t2 = mktime(&tms[1]); /* local */
28588 if (t1 == (time_t) -1 || t2 == (time_t) -1) {
28589 /* This check used to be for (t < 0) but on some platforms
28590 * time_t is unsigned and apparently the proper way to detect
28591 * an mktime() error return is the cast above. See e.g.:
28592 * http://pubs.opengroup.org/onlinepubs/009695299/functions/mktime.html
28593 */
28594 goto error;
28595 }
28596 DUK_DDD(DUK_DDDPRINT("t1=%ld (utc), t2=%ld (local)", (long) t1, (long) t2));
28597
28598 /* Compute final offset in seconds, positive if local time ahead of
28599 * UTC (returned value is UTC-to-local offset).
28600 *
28601 * difftime() returns a double, so coercion to int generates quite
28602 * a lot of code. Direct subtraction is not portable, however.
28603 * XXX: allow direct subtraction on known platforms.
28604 */
28605#if 0
28606 return (duk_int_t) (t2 - t1);
28607#endif
28608 return (duk_int_t) difftime(t2, t1);
28609
28610 error:
28611 /* XXX: return something more useful, so that caller can throw? */
28612 DUK_D(DUK_DPRINT("mktime() failed, d=%lf", (double) d));
28613 return 0;
28614}
28615#endif /* DUK_USE_DATE_TZO_GMTIME */
28616
28617#if defined(DUK_USE_DATE_PRS_STRPTIME)
28618DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_strptime(duk_context *ctx, const char *str) {
28619 struct tm tm;
28620 time_t t;
28621 char buf[DUK__STRPTIME_BUF_SIZE];
28622
28623 /* copy to buffer with spare to avoid Valgrind gripes from strptime */
28624 DUK_ASSERT(str != NULL);
28625 DUK_MEMZERO(buf, sizeof(buf)); /* valgrind whine without this */
28626 DUK_SNPRINTF(buf, sizeof(buf), "%s", (const char *) str);
28627 buf[sizeof(buf) - 1] = (char) 0;
28628
28629 DUK_DDD(DUK_DDDPRINT("parsing: '%s'", (const char *) buf));
28630
28631 DUK_MEMZERO(&tm, sizeof(tm));
28632 if (strptime((const char *) buf, "%c", &tm) != NULL) {
28633 DUK_DDD(DUK_DDDPRINT("before mktime: tm={sec:%ld,min:%ld,hour:%ld,mday:%ld,mon:%ld,year:%ld,"
28634 "wday:%ld,yday:%ld,isdst:%ld}",
28635 (long) tm.tm_sec, (long) tm.tm_min, (long) tm.tm_hour,
28636 (long) tm.tm_mday, (long) tm.tm_mon, (long) tm.tm_year,
28637 (long) tm.tm_wday, (long) tm.tm_yday, (long) tm.tm_isdst));
28638 tm.tm_isdst = -1; /* negative: dst info not available */
28639
28640 t = mktime(&tm);
28641 DUK_DDD(DUK_DDDPRINT("mktime() -> %ld", (long) t));
28642 if (t >= 0) {
28643 duk_push_number(ctx, ((duk_double_t) t) * 1000.0);
28644 return 1;
28645 }
28646 }
28647
28648 return 0;
28649}
28650#endif /* DUK_USE_DATE_PRS_STRPTIME */
28651
28652#if defined(DUK_USE_DATE_PRS_GETDATE)
28653DUK_INTERNAL duk_bool_t duk_bi_date_parse_string_getdate(duk_context *ctx, const char *str) {
28654 struct tm tm;
28655 duk_small_int_t rc;
28656 time_t t;
28657
28658 /* For this to work, DATEMSK must be set, so this is not very
28659 * convenient for an embeddable interpreter.
28660 */
28661
28662 DUK_MEMZERO(&tm, sizeof(struct tm));
28663 rc = (duk_small_int_t) getdate_r(str, &tm);
28664 DUK_DDD(DUK_DDDPRINT("getdate_r() -> %ld", (long) rc));
28665
28666 if (rc == 0) {
28667 t = mktime(&tm);
28668 DUK_DDD(DUK_DDDPRINT("mktime() -> %ld", (long) t));
28669 if (t >= 0) {
28670 duk_push_number(ctx, (duk_double_t) t);
28671 return 1;
28672 }
28673 }
28674
28675 return 0;
28676}
28677#endif /* DUK_USE_DATE_PRS_GETDATE */
28678
28679#if defined(DUK_USE_DATE_FMT_STRFTIME)
28680DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_context *ctx, duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags) {
28681 char buf[DUK__STRFTIME_BUF_SIZE];
28682 struct tm tm;
28683 const char *fmt;
28684
28685 DUK_UNREF(tzoffset);
28686
28687 /* If the platform doesn't support the entire Ecmascript range, we need
28688 * to return 0 so that the caller can fall back to the default formatter.
28689 *
28690 * For now, assume that if time_t is 8 bytes or more, the whole Ecmascript
28691 * range is supported. For smaller time_t values (4 bytes in practice),
28692 * assumes that the signed 32-bit range is supported.
28693 *
28694 * XXX: detect this more correctly per platform. The size of time_t is
28695 * probably not an accurate guarantee of strftime() supporting or not
28696 * supporting a large time range (the full Ecmascript range).
28697 */
28698 if (sizeof(time_t) < 8 &&
28699 (parts[DUK_DATE_IDX_YEAR] < 1970 || parts[DUK_DATE_IDX_YEAR] > 2037)) {
28700 /* be paranoid for 32-bit time values (even avoiding negative ones) */
28701 return 0;
28702 }
28703
28704 DUK_MEMZERO(&tm, sizeof(tm));
28705 tm.tm_sec = parts[DUK_DATE_IDX_SECOND];
28706 tm.tm_min = parts[DUK_DATE_IDX_MINUTE];
28707 tm.tm_hour = parts[DUK_DATE_IDX_HOUR];
28708 tm.tm_mday = parts[DUK_DATE_IDX_DAY]; /* already one-based */
28709 tm.tm_mon = parts[DUK_DATE_IDX_MONTH] - 1; /* one-based -> zero-based */
28710 tm.tm_year = parts[DUK_DATE_IDX_YEAR] - 1900;
28711 tm.tm_wday = parts[DUK_DATE_IDX_WEEKDAY];
28712 tm.tm_isdst = 0;
28713
28714 DUK_MEMZERO(buf, sizeof(buf));
28715 if ((flags & DUK_DATE_FLAG_TOSTRING_DATE) && (flags & DUK_DATE_FLAG_TOSTRING_TIME)) {
28716 fmt = "%c";
28717 } else if (flags & DUK_DATE_FLAG_TOSTRING_DATE) {
28718 fmt = "%x";
28719 } else {
28720 DUK_ASSERT(flags & DUK_DATE_FLAG_TOSTRING_TIME);
28721 fmt = "%X";
28722 }
28723 (void) strftime(buf, sizeof(buf) - 1, fmt, &tm);
28724 DUK_ASSERT(buf[sizeof(buf) - 1] == 0);
28725
28726 duk_push_string(ctx, buf);
28727 return 1;
28728}
28729#endif /* DUK_USE_DATE_FMT_STRFTIME */
28730
28731/* automatic undefs */
28732#undef DUK__STRFTIME_BUF_SIZE
28733#undef DUK__STRPTIME_BUF_SIZE
28734/*
28735 * Windows Date providers
28736 *
28737 * Platform specific links:
28738 *
28739 * - http://msdn.microsoft.com/en-us/library/windows/desktop/ms725473(v=vs.85).aspx
28740 */
28741
28742/* #include duk_internal.h -> already included */
28743
28744/* The necessary #includes are in place in duk_config.h. */
28745
28746#if defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS)
28747/* Shared Windows helpers. */
28748DUK_LOCAL void duk__convert_systime_to_ularge(const SYSTEMTIME *st, ULARGE_INTEGER *res) {
28749 FILETIME ft;
28750 if (SystemTimeToFileTime(st, &ft) == 0) {
28751 DUK_D(DUK_DPRINT("SystemTimeToFileTime() failed, returning 0"));
28752 res->QuadPart = 0;
28753 } else {
28754 res->LowPart = ft.dwLowDateTime;
28755 res->HighPart = ft.dwHighDateTime;
28756 }
28757}
28758DUK_LOCAL void duk__set_systime_jan1970(SYSTEMTIME *st) {
28759 DUK_MEMZERO((void *) st, sizeof(*st));
28760 st->wYear = 1970;
28761 st->wMonth = 1;
28762 st->wDayOfWeek = 4; /* not sure whether or not needed; Thursday */
28763 st->wDay = 1;
28764 DUK_ASSERT(st->wHour == 0);
28765 DUK_ASSERT(st->wMinute == 0);
28766 DUK_ASSERT(st->wSecond == 0);
28767 DUK_ASSERT(st->wMilliseconds == 0);
28768}
28769#endif /* defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS) */
28770
28771#if defined(DUK_USE_DATE_NOW_WINDOWS)
28772DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows(duk_context *ctx) {
28773 /* Suggested step-by-step method from documentation of RtlTimeToSecondsSince1970:
28774 * http://msdn.microsoft.com/en-us/library/windows/desktop/ms724928(v=vs.85).aspx
28775 */
28776 SYSTEMTIME st1, st2;
28777 ULARGE_INTEGER tmp1, tmp2;
28778
28779 DUK_UNREF(ctx);
28780
28781 GetSystemTime(&st1);
28782 duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
28783
28784 duk__set_systime_jan1970(&st2);
28785 duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);
28786
28787 /* Difference is in 100ns units, convert to milliseconds w/o fractions */
28788 return (duk_double_t) ((tmp1.QuadPart - tmp2.QuadPart) / 10000LL);
28789}
28790#endif /* DUK_USE_DATE_NOW_WINDOWS */
28791
28792
28793#if defined(DUK_USE_DATE_TZO_WINDOWS)
28794DUK_INTERNAL_DECL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d) {
28795 SYSTEMTIME st1;
28796 SYSTEMTIME st2;
28797 SYSTEMTIME st3;
28798 ULARGE_INTEGER tmp1;
28799 ULARGE_INTEGER tmp2;
28800 ULARGE_INTEGER tmp3;
28801 FILETIME ft1;
28802
28803 /* XXX: handling of timestamps outside Windows supported range.
28804 * How does Windows deal with dates before 1600? Does windows
28805 * support all Ecmascript years (like -200000 and +200000)?
28806 * Should equivalent year mapping be used here too? If so, use
28807 * a shared helper (currently integrated into timeval-to-parts).
28808 */
28809
28810 /* Use the approach described in "Remarks" of FileTimeToLocalFileTime:
28811 * http://msdn.microsoft.com/en-us/library/windows/desktop/ms724277(v=vs.85).aspx
28812 */
28813
28814 duk__set_systime_jan1970(&st1);
28815 duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
28816 tmp2.QuadPart = (ULONGLONG) (d * 10000.0); /* millisec -> 100ns units since jan 1, 1970 */
28817 tmp2.QuadPart += tmp1.QuadPart; /* input 'd' in Windows UTC, 100ns units */
28818
28819 ft1.dwLowDateTime = tmp2.LowPart;
28820 ft1.dwHighDateTime = tmp2.HighPart;
28821 FileTimeToSystemTime((const FILETIME *) &ft1, &st2);
28822 if (SystemTimeToTzSpecificLocalTime((LPTIME_ZONE_INFORMATION) NULL, &st2, &st3) == 0) {
28823 DUK_D(DUK_DPRINT("SystemTimeToTzSpecificLocalTime() failed, return tzoffset 0"));
28824 return 0;
28825 }
28826 duk__convert_systime_to_ularge((const SYSTEMTIME *) &st3, &tmp3);
28827
28828 /* Positive if local time ahead of UTC. */
28829 return (duk_int_t) (((LONGLONG) tmp3.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000000LL); /* seconds */
28830}
28831#endif /* DUK_USE_DATE_TZO_WINDOWS */
28832/*
28833 * Duktape built-ins
28834 *
28835 * Size optimization note: it might seem that vararg multipurpose functions
28836 * like fin(), enc(), and dec() are not very size optimal, but using a single
28837 * user-visible Ecmascript function saves a lot of run-time footprint; each
28838 * Function instance takes >100 bytes. Using a shared native helper and a
28839 * 'magic' value won't save much if there are multiple Function instances
28840 * anyway.
28841 */
28842
28843/* #include duk_internal.h -> already included */
28844
28845#if defined(DUK_USE_DUKTAPE_BUILTIN)
28846
28847DUK_INTERNAL duk_ret_t duk_bi_duktape_object_info(duk_context *ctx) {
28848 duk_inspect_value(ctx, -1);
28849 return 1;
28850}
28851
28852DUK_INTERNAL duk_ret_t duk_bi_duktape_object_act(duk_context *ctx) {
28853 duk_int_t level;
28854
28855 level = duk_to_int(ctx, 0);
28856 duk_inspect_callstack_entry(ctx, level);
28857 return 1;
28858}
28859
28860DUK_INTERNAL duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx) {
28861 duk_hthread *thr = (duk_hthread *) ctx;
28862 duk_small_uint_t flags;
28863 duk_bool_t rc;
28864
28865 flags = (duk_small_uint_t) duk_get_uint(ctx, 0);
28866 rc = duk_heap_mark_and_sweep(thr->heap, flags);
28867
28868 /* XXX: Not sure what the best return value would be in the API.
28869 * Return a boolean for now. Note that rc == 0 is success (true).
28870 */
28871 duk_push_boolean(ctx, !rc);
28872 return 1;
28873}
28874
28875#if defined(DUK_USE_FINALIZER_SUPPORT)
28876DUK_INTERNAL duk_ret_t duk_bi_duktape_object_fin(duk_context *ctx) {
28877 (void) duk_require_hobject(ctx, 0);
28878 if (duk_get_top(ctx) >= 2) {
28879 /* Set: currently a finalizer is disabled by setting it to
28880 * undefined; this does not remove the property at the moment.
28881 * The value could be type checked to be either a function
28882 * or something else; if something else, the property could
28883 * be deleted.
28884 */
28885 duk_set_top(ctx, 2);
28886 (void) duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_INT_FINALIZER);
28887 return 0;
28888 } else {
28889 /* Get. */
28890 DUK_ASSERT(duk_get_top(ctx) == 1);
28891 duk_get_prop_stridx_short(ctx, 0, DUK_STRIDX_INT_FINALIZER);
28892 return 1;
28893 }
28894}
28895#endif /* DUK_USE_FINALIZER_SUPPORT */
28896
28897DUK_INTERNAL duk_ret_t duk_bi_duktape_object_enc(duk_context *ctx) {
28898 duk_hthread *thr = (duk_hthread *) ctx;
28899 duk_hstring *h_str;
28900
28901 DUK_UNREF(thr);
28902
28903 /* Vararg function: must be careful to check/require arguments.
28904 * The JSON helpers accept invalid indices and treat them like
28905 * non-existent optional parameters.
28906 */
28907
28908 h_str = duk_require_hstring(ctx, 0); /* Could reject symbols, but no point: won't match comparisons. */
28909 duk_require_valid_index(ctx, 1);
28910
28911 if (h_str == DUK_HTHREAD_STRING_HEX(thr)) {
28912 duk_set_top(ctx, 2);
28913 duk_hex_encode(ctx, 1);
28914 DUK_ASSERT_TOP(ctx, 2);
28915 } else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) {
28916 duk_set_top(ctx, 2);
28917 duk_base64_encode(ctx, 1);
28918 DUK_ASSERT_TOP(ctx, 2);
28919#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JX)
28920 } else if (h_str == DUK_HTHREAD_STRING_JX(thr)) {
28921 duk_bi_json_stringify_helper(ctx,
28922 1 /*idx_value*/,
28923 2 /*idx_replacer*/,
28924 3 /*idx_space*/,
28925 DUK_JSON_FLAG_EXT_CUSTOM |
28926 DUK_JSON_FLAG_ASCII_ONLY |
28927 DUK_JSON_FLAG_AVOID_KEY_QUOTES /*flags*/);
28928#endif
28929#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JC)
28930 } else if (h_str == DUK_HTHREAD_STRING_JC(thr)) {
28931 duk_bi_json_stringify_helper(ctx,
28932 1 /*idx_value*/,
28933 2 /*idx_replacer*/,
28934 3 /*idx_space*/,
28935 DUK_JSON_FLAG_EXT_COMPATIBLE |
28936 DUK_JSON_FLAG_ASCII_ONLY /*flags*/);
28937#endif
28938 } else {
28939 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
28940 }
28941 return 1;
28942}
28943
28944DUK_INTERNAL duk_ret_t duk_bi_duktape_object_dec(duk_context *ctx) {
28945 duk_hthread *thr = (duk_hthread *) ctx;
28946 duk_hstring *h_str;
28947
28948 DUK_UNREF(thr);
28949
28950 /* Vararg function: must be careful to check/require arguments.
28951 * The JSON helpers accept invalid indices and treat them like
28952 * non-existent optional parameters.
28953 */
28954
28955 h_str = duk_require_hstring(ctx, 0); /* Could reject symbols, but no point: won't match comparisons */
28956 duk_require_valid_index(ctx, 1);
28957
28958 if (h_str == DUK_HTHREAD_STRING_HEX(thr)) {
28959 duk_set_top(ctx, 2);
28960 duk_hex_decode(ctx, 1);
28961 DUK_ASSERT_TOP(ctx, 2);
28962 } else if (h_str == DUK_HTHREAD_STRING_BASE64(thr)) {
28963 duk_set_top(ctx, 2);
28964 duk_base64_decode(ctx, 1);
28965 DUK_ASSERT_TOP(ctx, 2);
28966#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JX)
28967 } else if (h_str == DUK_HTHREAD_STRING_JX(thr)) {
28968 duk_bi_json_parse_helper(ctx,
28969 1 /*idx_value*/,
28970 2 /*idx_replacer*/,
28971 DUK_JSON_FLAG_EXT_CUSTOM /*flags*/);
28972#endif
28973#if defined(DUK_USE_JSON_SUPPORT) && defined(DUK_USE_JC)
28974 } else if (h_str == DUK_HTHREAD_STRING_JC(thr)) {
28975 duk_bi_json_parse_helper(ctx,
28976 1 /*idx_value*/,
28977 2 /*idx_replacer*/,
28978 DUK_JSON_FLAG_EXT_COMPATIBLE /*flags*/);
28979#endif
28980 } else {
28981 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
28982 }
28983 return 1;
28984}
28985
28986/*
28987 * Compact an object
28988 */
28989
28990DUK_INTERNAL duk_ret_t duk_bi_duktape_object_compact(duk_context *ctx) {
28991 DUK_ASSERT_TOP(ctx, 1);
28992 duk_compact(ctx, 0);
28993 return 1; /* return the argument object */
28994}
28995
28996#endif /* DUK_USE_DUKTAPE_BUILTIN */
28997/*
28998 * WHATWG Encoding API built-ins
28999 *
29000 * API specification: https://encoding.spec.whatwg.org/#api
29001 * Web IDL: https://www.w3.org/TR/WebIDL/
29002 */
29003
29004/* #include duk_internal.h -> already included */
29005
29006/*
29007 * Data structures for encoding/decoding
29008 */
29009
29010typedef struct {
29011 duk_uint8_t *out; /* where to write next byte(s) */
29012 duk_codepoint_t lead; /* lead surrogate */
29014
29015typedef struct {
29016 /* UTF-8 decoding state */
29017 duk_codepoint_t codepoint; /* built up incrementally */
29018 duk_uint8_t upper; /* max value of next byte (decode error otherwise) */
29019 duk_uint8_t lower; /* min value of next byte (ditto) */
29020 duk_uint8_t needed; /* how many more bytes we need */
29021 duk_uint8_t bom_handled; /* BOM seen or no longer expected */
29022
29023 /* Decoder configuration */
29024 duk_uint8_t fatal;
29025 duk_uint8_t ignore_bom;
29027
29028/* The signed duk_codepoint_t type is used to signal a decoded codepoint
29029 * (>= 0) or various other states using negative values.
29030 */
29031#define DUK__CP_CONTINUE (-1) /* continue to next byte, no completed codepoint */
29032#define DUK__CP_ERROR (-2) /* decoding error */
29033#define DUK__CP_RETRY (-3) /* decoding error; retry last byte */
29034
29035/*
29036 * Raw helpers for encoding/decoding
29037 */
29038
29039/* Emit UTF-8 (= CESU-8) encoded U+FFFD (replacement char), i.e. ef bf bd. */
29040DUK_LOCAL duk_uint8_t *duk__utf8_emit_repl(duk_uint8_t *ptr) {
29041 *ptr++ = 0xef;
29042 *ptr++ = 0xbf;
29043 *ptr++ = 0xbd;
29044 return ptr;
29045}
29046
29047DUK_LOCAL void duk__utf8_decode_init(duk__decode_context *dec_ctx) {
29048 /* (Re)init the decoding state of 'dec_ctx' but leave decoder
29049 * configuration fields untouched.
29050 */
29051 dec_ctx->codepoint = 0x0000L;
29052 dec_ctx->upper = 0xbf;
29053 dec_ctx->lower = 0x80;
29054 dec_ctx->needed = 0;
29055 dec_ctx->bom_handled = 0;
29056}
29057
29058DUK_LOCAL duk_codepoint_t duk__utf8_decode_next(duk__decode_context *dec_ctx, duk_uint8_t x) {
29059 /*
29060 * UTF-8 algorithm based on the Encoding specification:
29061 * https://encoding.spec.whatwg.org/#utf-8-decoder
29062 *
29063 * Two main states: decoding initial byte vs. decoding continuation
29064 * bytes. Shortest length encoding is validated by restricting the
29065 * allowed range of first continuation byte using 'lower' and 'upper'.
29066 */
29067
29068 if (dec_ctx->needed == 0) {
29069 /* process initial byte */
29070 if (x <= 0x7f) {
29071 /* U+0000-U+007F, 1 byte (ASCII) */
29072 return (duk_codepoint_t) x;
29073 } else if (x >= 0xc2 && x <= 0xdf) {
29074 /* U+0080-U+07FF, 2 bytes */
29075 dec_ctx->needed = 1;
29076 dec_ctx->codepoint = x & 0x1f;
29077 DUK_ASSERT(dec_ctx->lower == 0x80);
29078 DUK_ASSERT(dec_ctx->upper == 0xbf);
29079 return DUK__CP_CONTINUE;
29080 } else if (x >= 0xe0 && x <= 0xef) {
29081 /* U+0800-U+FFFF, 3 bytes */
29082 if (x == 0xe0) {
29083 dec_ctx->lower = 0xa0;
29084 DUK_ASSERT(dec_ctx->upper == 0xbf);
29085 } else if (x == 0xed) {
29086 DUK_ASSERT(dec_ctx->lower == 0x80);
29087 dec_ctx->upper = 0x9f;
29088 }
29089 dec_ctx->needed = 2;
29090 dec_ctx->codepoint = x & 0x0f;
29091 return DUK__CP_CONTINUE;
29092 } else if (x >= 0xf0 && x <= 0xf4) {
29093 /* U+010000-U+10FFFF, 4 bytes */
29094 if (x == 0xf0) {
29095 dec_ctx->lower = 0x90;
29096 DUK_ASSERT(dec_ctx->upper == 0xbf);
29097 } else if (x == 0xf4) {
29098 DUK_ASSERT(dec_ctx->lower == 0x80);
29099 dec_ctx->upper = 0x8f;
29100 }
29101 dec_ctx->needed = 3;
29102 dec_ctx->codepoint = x & 0x07;
29103 return DUK__CP_CONTINUE;
29104 } else {
29105 /* not a legal initial byte */
29106 return DUK__CP_ERROR;
29107 }
29108 } else {
29109 /* process continuation byte */
29110 if (x >= dec_ctx->lower && x <= dec_ctx->upper) {
29111 dec_ctx->lower = 0x80;
29112 dec_ctx->upper = 0xbf;
29113 dec_ctx->codepoint = (dec_ctx->codepoint << 6) | (x & 0x3f);
29114 if (--dec_ctx->needed > 0) {
29115 /* need more bytes */
29116 return DUK__CP_CONTINUE;
29117 } else {
29118 /* got a codepoint */
29119 duk_codepoint_t ret;
29120 DUK_ASSERT(dec_ctx->codepoint <= 0x10ffffL); /* Decoding rules guarantee. */
29121 ret = dec_ctx->codepoint;
29122 dec_ctx->codepoint = 0x0000L;
29123 dec_ctx->needed = 0;
29124 return ret;
29125 }
29126 } else {
29127 /* We just encountered an illegal UTF-8 continuation byte. This might
29128 * be the initial byte of the next character; if we return a plain
29129 * error status and the decoder is in replacement mode, the character
29130 * will be masked. We still need to alert the caller to the error
29131 * though.
29132 */
29133 dec_ctx->codepoint = 0x0000L;
29134 dec_ctx->needed = 0;
29135 dec_ctx->lower = 0x80;
29136 dec_ctx->upper = 0xbf;
29137 return DUK__CP_RETRY;
29138 }
29139 }
29140}
29141
29142DUK_LOCAL void duk__utf8_encode_char(void *udata, duk_codepoint_t codepoint) {
29143 duk__encode_context *enc_ctx;
29144
29145 DUK_ASSERT(codepoint >= 0);
29146 enc_ctx = (duk__encode_context *) udata;
29147 DUK_ASSERT(enc_ctx != NULL);
29148
29149#if !defined(DUK_USE_PREFER_SIZE)
29150 if (codepoint <= 0x7f && enc_ctx->lead == 0x0000L) {
29151 /* Fast path for ASCII. */
29152 *enc_ctx->out++ = (duk_uint8_t) codepoint;
29153 return;
29154 }
29155#endif
29156
29157 if (DUK_UNLIKELY(codepoint > 0x10ffffL)) {
29158 /* cannot legally encode in UTF-8 */
29159 codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
29160 } else if (codepoint >= 0xd800L && codepoint <= 0xdfffL) {
29161 if (codepoint <= 0xdbffL) {
29162 /* high surrogate */
29163 duk_codepoint_t prev_lead = enc_ctx->lead;
29164 enc_ctx->lead = codepoint;
29165 if (prev_lead == 0x0000L) {
29166 /* high surrogate, no output */
29167 return;
29168 } else {
29169 /* consecutive high surrogates, consider first one unpaired */
29170 codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
29171 }
29172 } else {
29173 /* low surrogate */
29174 if (enc_ctx->lead != 0x0000L) {
29175 codepoint = 0x010000L + ((enc_ctx->lead - 0xd800L) << 10) + (codepoint - 0xdc00L);
29176 enc_ctx->lead = 0x0000L;
29177 } else {
29178 /* unpaired low surrogate */
29179 DUK_ASSERT(enc_ctx->lead == 0x0000L);
29180 codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
29181 }
29182 }
29183 } else {
29184 if (enc_ctx->lead != 0x0000L) {
29185 /* unpaired high surrogate: emit replacement character and the input codepoint */
29186 enc_ctx->lead = 0x0000L;
29187 enc_ctx->out = duk__utf8_emit_repl(enc_ctx->out);
29188 }
29189 }
29190
29191 /* Codepoint may be original input, a decoded surrogate pair, or may
29192 * have been replaced with U+FFFD.
29193 */
29194 enc_ctx->out += duk_unicode_encode_xutf8(codepoint, enc_ctx->out);
29195}
29196
29197/* Shared helper for buffer-to-string using a TextDecoder() compatible UTF-8
29198 * decoder.
29199 */
29200DUK_LOCAL duk_ret_t duk__decode_helper(duk_context *ctx, duk__decode_context *dec_ctx) {
29201 const duk_uint8_t *input;
29202 duk_size_t len = 0;
29203 duk_size_t len_tmp;
29204 duk_bool_t stream = 0;
29205 duk_codepoint_t codepoint;
29206 duk_uint8_t *output;
29207 const duk_uint8_t *in;
29208 duk_uint8_t *out;
29209
29210 DUK_ASSERT(dec_ctx != NULL);
29211
29212 /* Careful with input buffer pointer: any side effects involving
29213 * code execution (e.g. getters, coercion calls, and finalizers)
29214 * may cause a resize and invalidate a pointer we've read. This
29215 * is why the pointer is actually looked up at the last minute.
29216 * Argument validation must still happen first to match WHATWG
29217 * required side effect order.
29218 */
29219
29220 if (duk_is_undefined(ctx, 0)) {
29221 duk_push_fixed_buffer_nozero(ctx, 0);
29222 duk_replace(ctx, 0);
29223 }
29224 (void) duk_require_buffer_data(ctx, 0, &len); /* Need 'len', avoid pointer. */
29225
29226 if (duk_check_type_mask(ctx, 1, DUK_TYPE_MASK_UNDEFINED |
29227 DUK_TYPE_MASK_NULL |
29228 DUK_TYPE_MASK_NONE)) {
29229 /* Use defaults, treat missing value like undefined. */
29230 } else {
29231 duk_require_type_mask(ctx, 1, DUK_TYPE_MASK_UNDEFINED |
29232 DUK_TYPE_MASK_NULL |
29233 DUK_TYPE_MASK_LIGHTFUNC |
29234 DUK_TYPE_MASK_BUFFER |
29235 DUK_TYPE_MASK_OBJECT);
29236 if (duk_get_prop_string(ctx, 1, "stream")) {
29237 stream = duk_to_boolean(ctx, -1);
29238 }
29239 }
29240
29241 /* Allowance is 3*len in the general case because all bytes may potentially
29242 * become U+FFFD. If the first byte completes a non-BMP codepoint it will
29243 * decode to a CESU-8 surrogate pair (6 bytes) so we allow 3 extra bytes to
29244 * compensate: (1*3)+3 = 6. Non-BMP codepoints are safe otherwise because
29245 * the 4->6 expansion is well under the 3x allowance.
29246 *
29247 * XXX: As with TextEncoder, need a better buffer allocation strategy here.
29248 */
29249 if (len >= (DUK_HBUFFER_MAX_BYTELEN / 3) - 3) {
29250 DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_RESULT_TOO_LONG);
29251 }
29252 output = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, 3 + (3 * len)); /* used parts will be always manually written over */
29253
29254 input = (const duk_uint8_t *) duk_get_buffer_data(ctx, 0, &len_tmp);
29255 DUK_ASSERT(input != NULL || len == 0);
29256 if (DUK_UNLIKELY(len != len_tmp)) {
29257 /* Very unlikely but possible: source buffer was resized by
29258 * a side effect when fixed buffer was pushed. Output buffer
29259 * may not be large enough to hold output, so just fail if
29260 * length has changed.
29261 */
29262 DUK_D(DUK_DPRINT("input buffer resized by side effect, fail"));
29263 goto fail_type;
29264 }
29265
29266 /* From this point onwards it's critical that no side effect occur
29267 * which may disturb 'input': finalizer execution, property accesses,
29268 * active coercions, etc. Even an allocation related mark-and-sweep
29269 * may affect the pointer because it may trigger a pending finalizer.
29270 */
29271
29272 in = input;
29273 out = output;
29274 while (in < input + len) {
29275 codepoint = duk__utf8_decode_next(dec_ctx, *in++);
29276 if (codepoint < 0) {
29277 if (codepoint == DUK__CP_CONTINUE) {
29278 continue;
29279 }
29280
29281 /* Decoding error with or without retry. */
29282 DUK_ASSERT(codepoint == DUK__CP_ERROR || codepoint == DUK__CP_RETRY);
29283 if (codepoint == DUK__CP_RETRY) {
29284 --in; /* retry last byte */
29285 }
29286 /* replacement mode: replace with U+FFFD */
29287 codepoint = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
29288 if (dec_ctx->fatal) {
29289 /* fatal mode: throw a TypeError */
29290 goto fail_type;
29291 }
29292 /* Continue with 'codepoint', Unicode replacement. */
29293 }
29294 DUK_ASSERT(codepoint >= 0x0000L && codepoint <= 0x10ffffL);
29295
29296 if (!dec_ctx->bom_handled) {
29297 dec_ctx->bom_handled = 1;
29298 if (codepoint == 0xfeffL && !dec_ctx->ignore_bom) {
29299 continue;
29300 }
29301 }
29302
29303 out += duk_unicode_encode_cesu8(codepoint, out);
29304 DUK_ASSERT(out <= output + (3 + (3 * len)));
29305 }
29306
29307 if (!stream) {
29308 if (dec_ctx->needed != 0) {
29309 /* truncated sequence at end of buffer */
29310 if (dec_ctx->fatal) {
29311 goto fail_type;
29312 } else {
29313 out += duk_unicode_encode_cesu8(DUK_UNICODE_CP_REPLACEMENT_CHARACTER, out);
29314 DUK_ASSERT(out <= output + (3 + (3 * len)));
29315 }
29316 }
29317 duk__utf8_decode_init(dec_ctx); /* Initialize decoding state for potential reuse. */
29318 }
29319
29320 /* Output buffer is fixed and thus stable even if there had been
29321 * side effects (which there shouldn't be).
29322 */
29323 duk_push_lstring(ctx, (const char *) output, (duk_size_t) (out - output));
29324 return 1;
29325
29326 fail_type:
29327 DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_DECODE_FAILED);
29328 DUK_UNREACHABLE();
29329}
29330
29331/*
29332 * Built-in bindings
29333 */
29334
29335#if defined(DUK_USE_ENCODING_BUILTINS)
29336DUK_INTERNAL duk_ret_t duk_bi_textencoder_constructor(duk_context *ctx) {
29337 /* TextEncoder currently requires no persistent state, so the constructor
29338 * does nothing on purpose.
29339 */
29340
29341 duk_require_constructor_call(ctx);
29342 return 0;
29343}
29344
29345DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encoding_getter(duk_context *ctx) {
29346 duk_push_string(ctx, "utf-8");
29347 return 1;
29348}
29349
29350DUK_INTERNAL duk_ret_t duk_bi_textencoder_prototype_encode(duk_context *ctx) {
29351 duk__encode_context enc_ctx;
29352 duk_size_t len;
29353 duk_size_t final_len;
29354 duk_uint8_t *output;
29355
29356 DUK_ASSERT_TOP(ctx, 1);
29357 if (duk_is_undefined(ctx, 0)) {
29358 len = 0;
29359 final_len = len;
29360 } else {
29361 duk_hstring *h_input;
29362
29363 h_input = duk_to_hstring(ctx, 0);
29364 DUK_ASSERT(h_input != NULL);
29365
29366 len = (duk_size_t) DUK_HSTRING_GET_CHARLEN(h_input);
29367 if (len >= DUK_HBUFFER_MAX_BYTELEN / 3) {
29368 DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_RESULT_TOO_LONG);
29369 }
29370 }
29371
29372 /* Allowance is 3*len because all bytes can potentially be replaced with
29373 * U+FFFD -- which rather inconveniently encodes to 3 bytes in UTF-8.
29374 * Rely on dynamic buffer data pointer stability: no other code has
29375 * access to the data pointer.
29376 *
29377 * XXX: The buffer allocation strategy used here is rather inefficient.
29378 * Maybe switch to a chunk-based strategy, or preprocess the string to
29379 * figure out the space needed ahead of time?
29380 */
29381 DUK_ASSERT(3 * len >= len);
29382 output = (duk_uint8_t *) duk_push_dynamic_buffer(ctx, 3 * len);
29383
29384 if (len > 0) {
29385 DUK_ASSERT(duk_is_string(ctx, 0)); /* True if len > 0. */
29386
29387 /* XXX: duk_decode_string() is used to process the input
29388 * string. For standard Ecmascript strings, represented
29389 * internally as CESU-8, this is fine. However, behavior
29390 * beyond CESU-8 is not very strict: codepoints using an
29391 * extended form of UTF-8 are also accepted, and invalid
29392 * codepoint sequences (which are allowed in Duktape strings)
29393 * are not handled as well as they could (e.g. invalid
29394 * continuation bytes may mask following codepoints).
29395 * This is how Ecmascript code would also see such strings.
29396 * Maybe replace duk_decode_string() with an explicit strict
29397 * CESU-8 decoder here?
29398 */
29399 enc_ctx.lead = 0x0000L;
29400 enc_ctx.out = output;
29401 duk_decode_string(ctx, 0, duk__utf8_encode_char, (void *) &enc_ctx);
29402 if (enc_ctx.lead != 0x0000L) {
29403 /* unpaired high surrogate at end of string */
29404 enc_ctx.out = duk__utf8_emit_repl(enc_ctx.out);
29405 DUK_ASSERT(enc_ctx.out <= output + (3 * len));
29406 }
29407
29408 /* The output buffer is usually very much oversized, so shrink it to
29409 * actually needed size. Pointer stability assumed up to this point.
29410 */
29411 DUK_ASSERT_TOP(ctx, 2);
29412 DUK_ASSERT(output == (duk_uint8_t *) duk_get_buffer_data(ctx, -1, NULL));
29413
29414 final_len = (duk_size_t) (enc_ctx.out - output);
29415 duk_resize_buffer(ctx, -1, final_len);
29416 /* 'output' and 'enc_ctx.out' are potentially invalidated by the resize. */
29417 }
29418
29419 /* Standard WHATWG output is a Uint8Array. Here the Uint8Array will
29420 * be backed by a dynamic buffer which differs from e.g. Uint8Arrays
29421 * created as 'new Uint8Array(N)'. Ecmascript code won't see the
29422 * difference but C code will. When bufferobjects are not supported,
29423 * returns a plain dynamic buffer.
29424 */
29425#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
29426 duk_push_buffer_object(ctx, -1, 0, final_len, DUK_BUFOBJ_UINT8ARRAY);
29427#endif
29428 return 1;
29429}
29430
29431DUK_INTERNAL duk_ret_t duk_bi_textdecoder_constructor(duk_context *ctx) {
29432 duk__decode_context *dec_ctx;
29433 duk_bool_t fatal = 0;
29434 duk_bool_t ignore_bom = 0;
29435
29436 DUK_ASSERT_TOP(ctx, 2);
29437 duk_require_constructor_call(ctx);
29438 if (!duk_is_undefined(ctx, 0)) {
29439 /* XXX: For now ignore 'label' (encoding identifier). */
29440 duk_to_string(ctx, 0);
29441 }
29442 if (!duk_is_null_or_undefined(ctx, 1)) {
29443 if (duk_get_prop_string(ctx, 1, "fatal")) {
29444 fatal = duk_to_boolean(ctx, -1);
29445 }
29446 if (duk_get_prop_string(ctx, 1, "ignoreBOM")) {
29447 ignore_bom = duk_to_boolean(ctx, -1);
29448 }
29449 }
29450
29451 duk_push_this(ctx);
29452
29453 /* The decode context is not assumed to be zeroed; all fields are
29454 * initialized explicitly.
29455 */
29456 dec_ctx = (duk__decode_context *) duk_push_fixed_buffer(ctx, sizeof(duk__decode_context));
29457 dec_ctx->fatal = fatal;
29458 dec_ctx->ignore_bom = ignore_bom;
29459 duk__utf8_decode_init(dec_ctx); /* Initializes remaining fields. */
29460
29461 duk_put_prop_string(ctx, -2, "\xff" "Context");
29462 return 0;
29463}
29464
29465/* Get TextDecoder context from 'this'; leaves garbage on stack. */
29466DUK_LOCAL duk__decode_context *duk__get_textdecoder_context(duk_context *ctx) {
29467 duk__decode_context *dec_ctx;
29468 duk_push_this(ctx);
29469 duk_get_prop_string(ctx, -1, "\xff" "Context");
29470 dec_ctx = (duk__decode_context *) duk_require_buffer(ctx, -1, NULL);
29471 DUK_ASSERT(dec_ctx != NULL);
29472 return dec_ctx;
29473}
29474
29475DUK_INTERNAL duk_ret_t duk_bi_textdecoder_prototype_shared_getter(duk_context *ctx) {
29476 duk__decode_context *dec_ctx;
29477 duk_int_t magic;
29478
29479 dec_ctx = duk__get_textdecoder_context(ctx);
29480 magic = duk_get_current_magic(ctx);
29481 switch (magic) {
29482 case 0:
29483 /* Encoding is now fixed, so _Context lookup is only needed to
29484 * validate the 'this' binding (TypeError if not TextDecoder-like).
29485 */
29486 duk_push_string(ctx, "utf-8");
29487 break;
29488 case 1:
29489 duk_push_boolean(ctx, dec_ctx->fatal);
29490 break;
29491 default:
29492 duk_push_boolean(ctx, dec_ctx->ignore_bom);
29493 break;
29494 }
29495
29496 return 1;
29497}
29498
29499DUK_INTERNAL duk_ret_t duk_bi_textdecoder_prototype_decode(duk_context *ctx) {
29500 duk__decode_context *dec_ctx;
29501
29502 dec_ctx = duk__get_textdecoder_context(ctx);
29503 return duk__decode_helper(ctx, dec_ctx);
29504}
29505#endif /* DUK_USE_ENCODING_BUILTINS */
29506
29507/*
29508 * Internal helper for Node.js Buffer
29509 */
29510
29511/* Internal helper used for Node.js Buffer .toString(). Value stack convention
29512 * is currently odd: it mimics TextDecoder .decode() so that argument must be at
29513 * index 0, and decode options (not present for Buffer) at index 1. Return value
29514 * is a Duktape/C function return value.
29515 */
29516DUK_INTERNAL duk_ret_t duk_textdecoder_decode_utf8_nodejs(duk_context *ctx) {
29517 duk__decode_context dec_ctx;
29518
29519 dec_ctx.fatal = 0; /* use replacement chars */
29520 dec_ctx.ignore_bom = 1; /* ignore BOMs (matches Node.js Buffer .toString()) */
29521 duk__utf8_decode_init(&dec_ctx);
29522
29523 return duk__decode_helper(ctx, &dec_ctx);
29524}
29525
29526/* automatic undefs */
29527#undef DUK__CP_CONTINUE
29528#undef DUK__CP_ERROR
29529#undef DUK__CP_RETRY
29530/*
29531 * Error built-ins
29532 */
29533
29534/* #include duk_internal.h -> already included */
29535
29536DUK_INTERNAL duk_ret_t duk_bi_error_constructor_shared(duk_context *ctx) {
29537 /* Behavior for constructor and non-constructor call is
29538 * the same except for augmenting the created error. When
29539 * called as a constructor, the caller (duk_new()) will handle
29540 * augmentation; when called as normal function, we need to do
29541 * it here.
29542 */
29543
29544 duk_hthread *thr = (duk_hthread *) ctx;
29545 duk_small_int_t bidx_prototype = duk_get_current_magic(ctx);
29546
29547 /* same for both error and each subclass like TypeError */
29548 duk_uint_t flags_and_class = DUK_HOBJECT_FLAG_EXTENSIBLE |
29549 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ERROR);
29550
29551 DUK_UNREF(thr);
29552
29553 (void) duk_push_object_helper(ctx, flags_and_class, bidx_prototype);
29554
29555 /* If message is undefined, the own property 'message' is not set at
29556 * all to save property space. An empty message is inherited anyway.
29557 */
29558 if (!duk_is_undefined(ctx, 0)) {
29559 duk_to_string(ctx, 0);
29560 duk_dup_0(ctx); /* [ message error message ] */
29561 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_MESSAGE, DUK_PROPDESC_FLAGS_WC);
29562 }
29563
29564 /* Augment the error if called as a normal function. __FILE__ and __LINE__
29565 * are not desirable in this case.
29566 */
29567
29568#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
29569 if (!duk_is_constructor_call(ctx)) {
29570 duk_err_augment_error_create(thr, thr, NULL, 0, 1 /*noblame_fileline*/);
29571 }
29572#endif
29573
29574 return 1;
29575}
29576
29577DUK_INTERNAL duk_ret_t duk_bi_error_prototype_to_string(duk_context *ctx) {
29578 /* XXX: optimize with more direct internal access */
29579
29580 duk_push_this(ctx);
29581 (void) duk_require_hobject_promote_mask(ctx, -1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
29582
29583 /* [ ... this ] */
29584
29585 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_NAME);
29586 if (duk_is_undefined(ctx, -1)) {
29587 duk_pop(ctx);
29588 duk_push_string(ctx, "Error");
29589 } else {
29590 duk_to_string(ctx, -1);
29591 }
29592
29593 /* [ ... this name ] */
29594
29595 /* XXX: Are steps 6 and 7 in E5 Section 15.11.4.4 duplicated by
29596 * accident or are they actually needed? The first ToString()
29597 * could conceivably return 'undefined'.
29598 */
29599 duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_MESSAGE);
29600 if (duk_is_undefined(ctx, -1)) {
29601 duk_pop(ctx);
29602 duk_push_hstring_empty(ctx);
29603 } else {
29604 duk_to_string(ctx, -1);
29605 }
29606
29607 /* [ ... this name message ] */
29608
29609 if (duk_get_length(ctx, -2) == 0) {
29610 /* name is empty -> return message */
29611 return 1;
29612 }
29613 if (duk_get_length(ctx, -1) == 0) {
29614 /* message is empty -> return name */
29615 duk_pop(ctx);
29616 return 1;
29617 }
29618 duk_push_string(ctx, ": ");
29619 duk_insert(ctx, -2); /* ... name ': ' message */
29620 duk_concat(ctx, 3);
29621
29622 return 1;
29623}
29624
29625#if defined(DUK_USE_TRACEBACKS)
29626
29627/*
29628 * Traceback handling
29629 *
29630 * The unified helper decodes the traceback and produces various requested
29631 * outputs. It should be optimized for size, and may leave garbage on stack,
29632 * only the topmost return value matters. For instance, traceback separator
29633 * and decoded strings are pushed even when looking for filename only.
29634 *
29635 * NOTE: although _Tracedata is an internal property, user code can currently
29636 * write to the array (or replace it with something other than an array).
29637 * The code below must tolerate arbitrary _Tracedata. It can throw errors
29638 * etc, but cannot cause a segfault or memory unsafe behavior.
29639 */
29640
29641/* constants arbitrary, chosen for small loads */
29642#define DUK__OUTPUT_TYPE_TRACEBACK (-1)
29643#define DUK__OUTPUT_TYPE_FILENAME 0
29644#define DUK__OUTPUT_TYPE_LINENUMBER 1
29645
29646DUK_LOCAL duk_ret_t duk__error_getter_helper(duk_context *ctx, duk_small_int_t output_type) {
29647 duk_hthread *thr = (duk_hthread *) ctx;
29648 duk_idx_t idx_td;
29649 duk_small_int_t i; /* traceback depth fits into 16 bits */
29650 duk_small_int_t t; /* stack type fits into 16 bits */
29651 duk_small_int_t count_func = 0; /* traceback depth ensures fits into 16 bits */
29652 const char *str_tailcall = " tailcall";
29653 const char *str_strict = " strict";
29654 const char *str_construct = " construct";
29655 const char *str_prevyield = " preventsyield";
29656 const char *str_directeval = " directeval";
29657 const char *str_empty = "";
29658
29659 DUK_ASSERT_TOP(ctx, 0); /* fixed arg count */
29660 DUK_UNREF(thr);
29661
29662 duk_push_this(ctx);
29663 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_TRACEDATA);
29664 idx_td = duk_get_top_index(ctx);
29665
29666 duk_push_hstring_stridx(ctx, DUK_STRIDX_NEWLINE_4SPACE);
29667 duk_push_this(ctx);
29668
29669 /* [ ... this tracedata sep this ] */
29670
29671 /* XXX: skip null filename? */
29672
29673 if (duk_check_type(ctx, idx_td, DUK_TYPE_OBJECT)) {
29674 /* Current tracedata contains 2 entries per callstack entry. */
29675 for (i = 0; ; i += 2) {
29676 duk_int_t pc;
29677 duk_int_t line;
29678 duk_int_t flags;
29679 duk_double_t d;
29680 const char *funcname;
29681 const char *filename;
29682 duk_hobject *h_func;
29683 duk_hstring *h_name;
29684
29685 duk_require_stack(ctx, 5);
29686 duk_get_prop_index(ctx, idx_td, i);
29687 duk_get_prop_index(ctx, idx_td, i + 1);
29688 d = duk_to_number_m1(ctx);
29689 pc = (duk_int_t) DUK_FMOD(d, DUK_DOUBLE_2TO32);
29690 flags = (duk_int_t) DUK_FLOOR(d / DUK_DOUBLE_2TO32);
29691 t = (duk_small_int_t) duk_get_type(ctx, -2);
29692
29693 if (t == DUK_TYPE_OBJECT || t == DUK_TYPE_LIGHTFUNC) {
29694 /*
29695 * Ecmascript/native function call or lightfunc call
29696 */
29697
29698 count_func++;
29699
29700 /* [ ... v1(func) v2(pc+flags) ] */
29701
29702 h_func = duk_get_hobject(ctx, -2); /* NULL for lightfunc */
29703
29704 /* These may be systematically omitted by Duktape
29705 * with certain config options, but allow user to
29706 * set them on a case-by-case basis.
29707 */
29708 duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_NAME);
29709 duk_get_prop_stridx_short(ctx, -3, DUK_STRIDX_FILE_NAME);
29710
29711#if defined(DUK_USE_PC2LINE)
29712 line = duk_hobject_pc2line_query(ctx, -4, (duk_uint_fast32_t) pc);
29713#else
29714 line = 0;
29715#endif
29716
29717 /* [ ... v1 v2 name filename ] */
29718
29719 /* When looking for .fileName/.lineNumber, blame first
29720 * function which has a .fileName.
29721 */
29722 if (duk_is_string_notsymbol(ctx, -1)) {
29723 if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
29724 return 1;
29725 } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
29726 duk_push_int(ctx, line);
29727 return 1;
29728 }
29729 }
29730
29731 /* XXX: Change 'anon' handling here too, to use empty string for anonymous functions? */
29732 /* XXX: Could be improved by coercing to a readable duk_tval (especially string escaping) */
29733 h_name = duk_get_hstring_notsymbol(ctx, -2); /* may be NULL */
29734 funcname = (h_name == NULL || h_name == DUK_HTHREAD_STRING_EMPTY_STRING(thr)) ?
29735 "[anon]" : (const char *) DUK_HSTRING_GET_DATA(h_name);
29736 filename = duk_get_string_notsymbol(ctx, -1);
29737 filename = filename ? filename : "";
29738 DUK_ASSERT(funcname != NULL);
29739 DUK_ASSERT(filename != NULL);
29740
29741 if (h_func == NULL) {
29742 duk_push_sprintf(ctx, "at %s light%s%s%s%s%s",
29743 (const char *) funcname,
29744 (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
29745 (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
29746 (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
29747 (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
29748 (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
29749 } else if (DUK_HOBJECT_HAS_NATFUNC(h_func)) {
29750 duk_push_sprintf(ctx, "at %s (%s) native%s%s%s%s%s",
29751 (const char *) funcname,
29752 (const char *) filename,
29753 (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
29754 (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
29755 (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
29756 (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
29757 (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
29758 } else {
29759 duk_push_sprintf(ctx, "at %s (%s:%ld)%s%s%s%s%s",
29760 (const char *) funcname,
29761 (const char *) filename,
29762 (long) line,
29763 (const char *) ((flags & DUK_ACT_FLAG_STRICT) ? str_strict : str_empty),
29764 (const char *) ((flags & DUK_ACT_FLAG_TAILCALLED) ? str_tailcall : str_empty),
29765 (const char *) ((flags & DUK_ACT_FLAG_CONSTRUCT) ? str_construct : str_empty),
29766 (const char *) ((flags & DUK_ACT_FLAG_DIRECT_EVAL) ? str_directeval : str_empty),
29767 (const char *) ((flags & DUK_ACT_FLAG_PREVENT_YIELD) ? str_prevyield : str_empty));
29768 }
29769 duk_replace(ctx, -5); /* [ ... v1 v2 name filename str ] -> [ ... str v2 name filename ] */
29770 duk_pop_3(ctx); /* -> [ ... str ] */
29771 } else if (t == DUK_TYPE_STRING) {
29772 const char *str_file;
29773
29774 /*
29775 * __FILE__ / __LINE__ entry, here 'pc' is line number directly.
29776 * Sometimes __FILE__ / __LINE__ is reported as the source for
29777 * the error (fileName, lineNumber), sometimes not.
29778 */
29779
29780 /* [ ... v1(filename) v2(line+flags) ] */
29781
29782 /* When looking for .fileName/.lineNumber, blame compilation
29783 * or C call site unless flagged not to do so.
29784 */
29785 if (!(flags & DUK_TB_FLAG_NOBLAME_FILELINE)) {
29786 if (output_type == DUK__OUTPUT_TYPE_FILENAME) {
29787 duk_pop(ctx);
29788 return 1;
29789 } else if (output_type == DUK__OUTPUT_TYPE_LINENUMBER) {
29790 duk_push_int(ctx, pc);
29791 return 1;
29792 }
29793 }
29794
29795 /* Tracedata is trusted but avoid any risk of using a NULL
29796 * for %s format because it has undefined behavior. Symbols
29797 * don't need to be explicitly rejected as they pose no memory
29798 * safety issues.
29799 */
29800 str_file = (const char *) duk_get_string(ctx, -2);
29801 duk_push_sprintf(ctx, "at [anon] (%s:%ld) internal",
29802 (const char *) (str_file ? str_file : "null"), (long) pc);
29803 duk_replace(ctx, -3); /* [ ... v1 v2 str ] -> [ ... str v2 ] */
29804 duk_pop(ctx); /* -> [ ... str ] */
29805 } else {
29806 /* unknown, ignore */
29807 duk_pop_2(ctx);
29808 break;
29809 }
29810 }
29811
29812 if (count_func >= DUK_USE_TRACEBACK_DEPTH) {
29813 /* Possibly truncated; there is no explicit truncation
29814 * marker so this is the best we can do.
29815 */
29816
29817 duk_push_hstring_stridx(ctx, DUK_STRIDX_BRACKETED_ELLIPSIS);
29818 }
29819 }
29820
29821 /* [ ... this tracedata sep this str1 ... strN ] */
29822
29823 if (output_type != DUK__OUTPUT_TYPE_TRACEBACK) {
29824 return 0;
29825 } else {
29826 /* The 'this' after 'sep' will get ToString() coerced by
29827 * duk_join() automatically. We don't want to do that
29828 * coercion when providing .fileName or .lineNumber (GH-254).
29829 */
29830 duk_join(ctx, duk_get_top(ctx) - (idx_td + 2) /*count, not including sep*/);
29831 return 1;
29832 }
29833}
29834
29835/* XXX: Output type could be encoded into native function 'magic' value to
29836 * save space. For setters the stridx could be encoded into 'magic'.
29837 */
29838
29839DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx) {
29840 return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_TRACEBACK);
29841}
29842
29843DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx) {
29844 return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_FILENAME);
29845}
29846
29847DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx) {
29848 return duk__error_getter_helper(ctx, DUK__OUTPUT_TYPE_LINENUMBER);
29849}
29850
29851#else /* DUK_USE_TRACEBACKS */
29852
29853/*
29854 * Traceback handling when tracebacks disabled.
29855 *
29856 * The fileName / lineNumber stubs are now necessary because built-in
29857 * data will include the accessor properties in Error.prototype. If those
29858 * are removed for builds without tracebacks, these can also be removed.
29859 * 'stack' should still be present and produce a ToString() equivalent:
29860 * this is useful for user code which prints a stacktrace and expects to
29861 * see something useful. A normal stacktrace also begins with a ToString()
29862 * of the error so this makes sense.
29863 */
29864
29865DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_getter(duk_context *ctx) {
29866 /* XXX: remove this native function and map 'stack' accessor
29867 * to the toString() implementation directly.
29868 */
29869 return duk_bi_error_prototype_to_string(ctx);
29870}
29871
29872DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_getter(duk_context *ctx) {
29873 DUK_UNREF(ctx);
29874 return 0;
29875}
29876
29877DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_getter(duk_context *ctx) {
29878 DUK_UNREF(ctx);
29879 return 0;
29880}
29881
29882#endif /* DUK_USE_TRACEBACKS */
29883
29884DUK_LOCAL duk_ret_t duk__error_setter_helper(duk_context *ctx, duk_small_uint_t stridx_key) {
29885 /* Attempt to write 'stack', 'fileName', 'lineNumber' works as if
29886 * user code called Object.defineProperty() to create an overriding
29887 * own property. This allows user code to overwrite .fileName etc
29888 * intuitively as e.g. "err.fileName = 'dummy'" as one might expect.
29889 * See https://github.com/svaarala/duktape/issues/387.
29890 */
29891
29892 DUK_ASSERT_TOP(ctx, 1); /* fixed arg count: value */
29893
29894 duk_push_this(ctx);
29895 duk_push_hstring_stridx(ctx, (duk_small_int_t) stridx_key);
29896 duk_dup_0(ctx);
29897
29898 /* [ ... obj key value ] */
29899
29900 DUK_DD(DUK_DDPRINT("error setter: %!T %!T %!T",
29901 duk_get_tval(ctx, -3), duk_get_tval(ctx, -2), duk_get_tval(ctx, -1)));
29902
29903 duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_VALUE |
29904 DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE |
29905 DUK_DEFPROP_HAVE_ENUMERABLE | /*not enumerable*/
29906 DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE);
29907 return 0;
29908}
29909
29910DUK_INTERNAL duk_ret_t duk_bi_error_prototype_stack_setter(duk_context *ctx) {
29911 return duk__error_setter_helper(ctx, DUK_STRIDX_STACK);
29912}
29913
29914DUK_INTERNAL duk_ret_t duk_bi_error_prototype_filename_setter(duk_context *ctx) {
29915 return duk__error_setter_helper(ctx, DUK_STRIDX_FILE_NAME);
29916}
29917
29918DUK_INTERNAL duk_ret_t duk_bi_error_prototype_linenumber_setter(duk_context *ctx) {
29919 return duk__error_setter_helper(ctx, DUK_STRIDX_LINE_NUMBER);
29920}
29921
29922/* automatic undefs */
29923#undef DUK__OUTPUT_TYPE_FILENAME
29924#undef DUK__OUTPUT_TYPE_LINENUMBER
29925#undef DUK__OUTPUT_TYPE_TRACEBACK
29926/*
29927 * Function built-ins
29928 */
29929
29930/* #include duk_internal.h -> already included */
29931
29932/* Needed even when Function built-in is disabled. */
29933DUK_INTERNAL duk_ret_t duk_bi_function_prototype(duk_context *ctx) {
29934 /* ignore arguments, return undefined (E5 Section 15.3.4) */
29935 DUK_UNREF(ctx);
29936 return 0;
29937}
29938
29939#if defined(DUK_USE_FUNCTION_BUILTIN)
29940DUK_INTERNAL duk_ret_t duk_bi_function_constructor(duk_context *ctx) {
29941 duk_hthread *thr = (duk_hthread *) ctx;
29942 duk_hstring *h_sourcecode;
29943 duk_idx_t nargs;
29944 duk_idx_t i;
29945 duk_small_uint_t comp_flags;
29946 duk_hcompfunc *func;
29947 duk_hobject *outer_lex_env;
29948 duk_hobject *outer_var_env;
29949
29950 /* normal and constructor calls have identical semantics */
29951
29952 nargs = duk_get_top(ctx);
29953 for (i = 0; i < nargs; i++) {
29954 duk_to_string(ctx, i); /* Rejects Symbols during coercion. */
29955 }
29956
29957 if (nargs == 0) {
29958 duk_push_hstring_empty(ctx);
29959 duk_push_hstring_empty(ctx);
29960 } else if (nargs == 1) {
29961 /* XXX: cover this with the generic >1 case? */
29962 duk_push_hstring_empty(ctx);
29963 } else {
29964 duk_insert(ctx, 0); /* [ arg1 ... argN-1 body] -> [body arg1 ... argN-1] */
29965 duk_push_string(ctx, ",");
29966 duk_insert(ctx, 1);
29967 duk_join(ctx, nargs - 1);
29968 }
29969
29970 /* [ body formals ], formals is comma separated list that needs to be parsed */
29971
29972 DUK_ASSERT_TOP(ctx, 2);
29973
29974 /* XXX: this placeholder is not always correct, but use for now.
29975 * It will fail in corner cases; see test-dev-func-cons-args.js.
29976 */
29977 duk_push_string(ctx, "function(");
29978 duk_dup_1(ctx);
29979 duk_push_string(ctx, "){");
29980 duk_dup_0(ctx);
29981 duk_push_string(ctx, "}");
29982 duk_concat(ctx, 5);
29983
29984 /* [ body formals source ] */
29985
29986 DUK_ASSERT_TOP(ctx, 3);
29987
29988 /* strictness is not inherited, intentional */
29989 comp_flags = DUK_JS_COMPILE_FLAG_FUNCEXPR;
29990
29991 duk_push_hstring_stridx(ctx, DUK_STRIDX_COMPILE); /* XXX: copy from caller? */ /* XXX: ignored now */
29992 h_sourcecode = duk_require_hstring(ctx, -2); /* no symbol check needed; -2 is concat'd code */
29993 duk_js_compile(thr,
29994 (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_sourcecode),
29995 (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sourcecode),
29996 comp_flags);
29997
29998 /* Force .name to 'anonymous' (ES2015). */
29999 duk_push_string(ctx, "anonymous");
30000 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
30001
30002 func = (duk_hcompfunc *) duk_known_hobject(ctx, -1);
30003 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) func));
30004 DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) func));
30005
30006 /* [ body formals source template ] */
30007
30008 /* only outer_lex_env matters, as functions always get a new
30009 * variable declaration environment.
30010 */
30011
30012 outer_lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
30013 outer_var_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
30014
30015 duk_js_push_closure(thr, func, outer_var_env, outer_lex_env, 1 /*add_auto_proto*/);
30016
30017 /* [ body formals source template closure ] */
30018
30019 return 1;
30020}
30021#endif /* DUK_USE_FUNCTION_BUILTIN */
30022
30023#if defined(DUK_USE_FUNCTION_BUILTIN)
30024DUK_INTERNAL duk_ret_t duk_bi_function_prototype_to_string(duk_context *ctx) {
30025 duk_tval *tv;
30026
30027 /*
30028 * E5 Section 15.3.4.2 places few requirements on the output of
30029 * this function: the result is implementation dependent, must
30030 * follow FunctionDeclaration syntax (in particular, must have a
30031 * name even for anonymous functions or functions with empty name).
30032 * The output does NOT need to compile into anything useful.
30033 *
30034 * E6 Section 19.2.3.5 changes the requirements completely: the
30035 * result must either eval() to a functionally equivalent object
30036 * OR eval() to a SyntaxError.
30037 *
30038 * We opt for the SyntaxError approach for now, with a syntax that
30039 * mimics V8's native function syntax:
30040 *
30041 * 'function cos() { [native code] }'
30042 *
30043 * but extended with [ecmascript code], [bound code], and
30044 * [lightfunc code].
30045 */
30046
30047 duk_push_this(ctx);
30048 tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
30049 DUK_ASSERT(tv != NULL);
30050
30051 if (DUK_TVAL_IS_OBJECT(tv)) {
30052 duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv);
30053 const char *func_name;
30054
30055 /* Function name: missing/undefined is mapped to empty string,
30056 * otherwise coerce to string. No handling for invalid identifier
30057 * characters or e.g. '{' in the function name. This doesn't
30058 * really matter as long as a SyntaxError results. Technically
30059 * if the name contained a suitable prefix followed by '//' it
30060 * might cause the result to parse without error.
30061 */
30062 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_NAME);
30063 if (duk_is_undefined(ctx, -1)) {
30064 func_name = "";
30065 } else {
30066 func_name = duk_to_string(ctx, -1);
30067 DUK_ASSERT(func_name != NULL);
30068 }
30069
30070 if (DUK_HOBJECT_IS_COMPFUNC(obj)) {
30071 duk_push_sprintf(ctx, "function %s() { [ecmascript code] }", (const char *) func_name);
30072 } else if (DUK_HOBJECT_IS_NATFUNC(obj)) {
30073 duk_push_sprintf(ctx, "function %s() { [native code] }", (const char *) func_name);
30074 } else if (DUK_HOBJECT_IS_BOUNDFUNC(obj)) {
30075 duk_push_sprintf(ctx, "function %s() { [bound code] }", (const char *) func_name);
30076 } else {
30077 goto type_error;
30078 }
30079 } else if (DUK_TVAL_IS_LIGHTFUNC(tv)) {
30080 duk_push_lightfunc_tostring(ctx, tv);
30081 } else {
30082 goto type_error;
30083 }
30084
30085 return 1;
30086
30087 type_error:
30088 DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
30089}
30090#endif
30091
30092#if defined(DUK_USE_FUNCTION_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
30093DUK_INTERNAL duk_ret_t duk_bi_function_prototype_apply(duk_context *ctx) {
30094 /*
30095 * magic = 0: Function.prototype.apply()
30096 * magic = 1: Reflect.apply()
30097 * magic = 2: Reflect.construct()
30098 */
30099
30100 duk_idx_t idx_args;
30101 duk_idx_t len;
30102 duk_idx_t i;
30103 duk_int_t magic;
30104 duk_idx_t nargs;
30105 duk_uint_t mask;
30106
30107 magic = duk_get_current_magic(ctx);
30108 switch (magic) {
30109 case 0: /* Function.prototype.apply() */
30110 DUK_ASSERT_TOP(ctx, 2); /* not a vararg function */
30111 duk_push_this(ctx);
30112 duk_insert(ctx, 0);
30113 /* Fall through intentionally for shared handling. */
30114 case 1: /* Reflect.apply(); Function.prototype.apply() after 'this' fixup. */
30115 DUK_ASSERT_TOP(ctx, 3); /* not a vararg function */
30116 idx_args = 2;
30117 duk_require_callable(ctx, 0);
30118 break;
30119 default: /* Reflect.construct() */
30120 DUK_ASSERT(magic == 2);
30121 duk_require_constructable(ctx, 0);
30122 nargs = duk_get_top(ctx);
30123 if (nargs < 2) {
30124 DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
30125 }
30126 if (nargs >= 3 && !duk_strict_equals(ctx, 0, 2)) {
30127 /* XXX: [[Construct]] newTarget currently unsupported */
30128 DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx);
30129 }
30130 idx_args = 1;
30131 break;
30132 }
30133
30134 if (magic != 2) {
30135 DUK_DDD(DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argArray=%!iT",
30136 (duk_tval *) duk_get_tval(ctx, 0),
30137 (duk_tval *) duk_get_tval(ctx, 1),
30138 (duk_tval *) duk_get_tval(ctx, 2)));
30139 } else {
30140 /* thisArg is not applicable for Reflect.construct(). */
30141 DUK_DDD(DUK_DDDPRINT("func=%!iT, argArray=%!iT",
30142 (duk_tval *) duk_get_tval(ctx, 0),
30143 (duk_tval *) duk_get_tval(ctx, 1)));
30144 }
30145
30146 /* [ func thisArg? argArray ] */
30147
30148 mask = duk_get_type_mask(ctx, idx_args);
30149 if (mask & (DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_UNDEFINED)) {
30150 DUK_DDD(DUK_DDDPRINT("argArray is null/undefined, no args"));
30151 len = 0;
30152 } else if (mask & DUK_TYPE_MASK_OBJECT) {
30153 DUK_DDD(DUK_DDDPRINT("argArray is an object"));
30154
30155 /* XXX: make this an internal helper */
30156 DUK_ASSERT(idx_args >= 0 && idx_args <= 0x7fffL); /* short variants would work, but avoid shifting */
30157 duk_get_prop_stridx(ctx, idx_args, DUK_STRIDX_LENGTH);
30158 len = (duk_idx_t) duk_to_uint32(ctx, -1); /* ToUint32() coercion required */
30159 duk_pop(ctx);
30160
30161 duk_require_stack(ctx, len);
30162
30163 DUK_DDD(DUK_DDDPRINT("argArray length is %ld", (long) len));
30164 for (i = 0; i < len; i++) {
30165 duk_get_prop_index(ctx, idx_args, i);
30166 }
30167 } else {
30168 goto type_error;
30169 }
30170 duk_remove(ctx, idx_args);
30171 DUK_ASSERT_TOP(ctx, idx_args + len);
30172
30173 /* [ func thisArg? arg1 ... argN ] */
30174
30175 if (magic != 2) {
30176 /* Function.prototype.apply() or Reflect.apply() */
30177 DUK_DDD(DUK_DDDPRINT("apply, func=%!iT, thisArg=%!iT, len=%ld",
30178 (duk_tval *) duk_get_tval(ctx, 0),
30179 (duk_tval *) duk_get_tval(ctx, 1),
30180 (long) len));
30181 duk_call_method(ctx, len);
30182 } else {
30183 /* Reflect.construct() */
30184 DUK_DDD(DUK_DDDPRINT("construct, func=%!iT, len=%ld",
30185 (duk_tval *) duk_get_tval(ctx, 0),
30186 (long) len));
30187 duk_new(ctx, len);
30188 }
30189 return 1;
30190
30191 type_error:
30192 DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
30193}
30194#endif
30195
30196#if defined(DUK_USE_FUNCTION_BUILTIN)
30197DUK_INTERNAL duk_ret_t duk_bi_function_prototype_call(duk_context *ctx) {
30198 duk_idx_t nargs;
30199
30200 /* Step 1 is not necessary because duk_call_method() will take
30201 * care of it.
30202 */
30203
30204 /* vararg function, thisArg needs special handling */
30205 nargs = duk_get_top(ctx); /* = 1 + arg count */
30206 if (nargs == 0) {
30207 duk_push_undefined(ctx);
30208 nargs++;
30209 }
30210 DUK_ASSERT(nargs >= 1);
30211
30212 /* [ thisArg arg1 ... argN ] */
30213
30214 duk_push_this(ctx); /* 'func' in the algorithm */
30215 duk_insert(ctx, 0);
30216
30217 /* [ func thisArg arg1 ... argN ] */
30218
30219 DUK_DDD(DUK_DDDPRINT("func=%!iT, thisArg=%!iT, argcount=%ld, top=%ld",
30220 (duk_tval *) duk_get_tval(ctx, 0),
30221 (duk_tval *) duk_get_tval(ctx, 1),
30222 (long) (nargs - 1),
30223 (long) duk_get_top(ctx)));
30224 duk_call_method(ctx, nargs - 1);
30225 return 1;
30226}
30227#endif /* DUK_USE_FUNCTION_BUILTIN */
30228
30229#if defined(DUK_USE_FUNCTION_BUILTIN)
30230/* XXX: the implementation now assumes "chained" bound functions,
30231 * whereas "collapsed" bound functions (where there is ever only
30232 * one bound function which directly points to a non-bound, final
30233 * function) would require a "collapsing" implementation which
30234 * merges argument lists etc here.
30235 */
30236DUK_INTERNAL duk_ret_t duk_bi_function_prototype_bind(duk_context *ctx) {
30237 duk_hthread *thr = (duk_hthread *) ctx;
30238 duk_hobject *h_bound;
30239 duk_hobject *h_target;
30240 duk_idx_t nargs;
30241 duk_idx_t i;
30242
30243 /* vararg function, careful arg handling (e.g. thisArg may not be present) */
30244 nargs = duk_get_top(ctx); /* = 1 + arg count */
30245 if (nargs == 0) {
30246 duk_push_undefined(ctx);
30247 nargs++;
30248 }
30249 DUK_ASSERT(nargs >= 1);
30250
30251 duk_push_this(ctx);
30252 duk_require_callable(ctx, -1);
30253
30254 /* [ thisArg arg1 ... argN func ] (thisArg+args == nargs total) */
30255 DUK_ASSERT_TOP(ctx, nargs + 1);
30256
30257 /* create bound function object */
30258 h_bound = duk_push_object_helper(ctx,
30259 DUK_HOBJECT_FLAG_EXTENSIBLE |
30260 DUK_HOBJECT_FLAG_BOUNDFUNC |
30261 DUK_HOBJECT_FLAG_CONSTRUCTABLE |
30262 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_FUNCTION),
30263 DUK_BIDX_FUNCTION_PROTOTYPE);
30264 DUK_ASSERT(h_bound != NULL);
30265
30266 /* [ thisArg arg1 ... argN func boundFunc ] */
30267 duk_dup_m2(ctx); /* func */
30268 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
30269
30270 duk_dup_0(ctx); /* thisArg */
30271 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE);
30272
30273 duk_push_array(ctx);
30274
30275 /* [ thisArg arg1 ... argN func boundFunc argArray ] */
30276
30277 for (i = 0; i < nargs - 1; i++) {
30278 duk_dup(ctx, 1 + i);
30279 duk_put_prop_index(ctx, -2, i);
30280 }
30281 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_ARGS, DUK_PROPDESC_FLAGS_NONE);
30282
30283 /* [ thisArg arg1 ... argN func boundFunc ] */
30284
30285 h_target = duk_get_hobject(ctx, -2);
30286
30287 /* internal prototype must be copied from the target */
30288 if (h_target != NULL) {
30289 /* For lightfuncs Function.prototype is used and is already in place. */
30290 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h_bound, DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_target));
30291 }
30292
30293 /* bound function 'length' property is interesting */
30294 if (h_target == NULL || /* lightfunc */
30295 DUK_HOBJECT_GET_CLASS_NUMBER(h_target) == DUK_HOBJECT_CLASS_FUNCTION) {
30296 /* For lightfuncs, simply read the virtual property. */
30297 duk_int_t tmp;
30298 duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_LENGTH);
30299 tmp = duk_to_int(ctx, -1) - (nargs - 1); /* step 15.a */
30300 duk_pop(ctx);
30301 duk_push_int(ctx, (tmp < 0 ? 0 : tmp));
30302 } else {
30303 duk_push_int(ctx, 0);
30304 }
30305 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C); /* attrs in E6 Section 9.2.4 */
30306
30307 /* caller and arguments must use the same thrower, [[ThrowTypeError]] */
30308 duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_CALLER);
30309 duk_xdef_prop_stridx_thrower(ctx, -1, DUK_STRIDX_LC_ARGUMENTS);
30310
30311 /* XXX: 'copy properties' API call? */
30312#if defined(DUK_USE_FUNC_NAME_PROPERTY)
30313 duk_push_string(ctx, "bound "); /* ES2015 19.2.3.2. */
30314 duk_get_prop_stridx_short(ctx, -3, DUK_STRIDX_NAME);
30315 if (!duk_is_string_notsymbol(ctx, -1)) {
30316 /* ES2015 has requirement to check that .name of target is a string
30317 * (also must check for Symbol); if not, targetName should be the
30318 * empty string. ES2015 19.2.3.2.
30319 */
30320 duk_pop(ctx);
30321 duk_push_hstring_empty(ctx);
30322 }
30323 duk_concat(ctx, 2);
30324 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
30325#endif
30326#if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
30327 duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_FILE_NAME);
30328 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C);
30329#endif
30330
30331 /* The 'strict' flag is copied to get the special [[Get]] of E5.1
30332 * Section 15.3.5.4 to apply when a 'caller' value is a strict bound
30333 * function. Not sure if this is correct, because the specification
30334 * is a bit ambiguous on this point but it would make sense.
30335 */
30336 if (h_target == NULL) {
30337 /* Lightfuncs are always strict. */
30338 DUK_HOBJECT_SET_STRICT(h_bound);
30339 } else if (DUK_HOBJECT_HAS_STRICT(h_target)) {
30340 DUK_HOBJECT_SET_STRICT(h_bound);
30341 }
30342 DUK_DDD(DUK_DDDPRINT("created bound function: %!iT", (duk_tval *) duk_get_tval(ctx, -1)));
30343
30344 return 1;
30345}
30346#endif /* DUK_USE_FUNCTION_BUILTIN */
30347/*
30348 * Global object built-ins
30349 */
30350
30351/* #include duk_internal.h -> already included */
30352
30353/*
30354 * Encoding/decoding helpers
30355 */
30356
30357/* XXX: Could add fast path (for each transform callback) with direct byte
30358 * lookups (no shifting) and no explicit check for x < 0x80 before table
30359 * lookup.
30360 */
30361
30362/* Macros for creating and checking bitmasks for character encoding.
30363 * Bit number is a bit counterintuitive, but minimizes code size.
30364 */
30365#define DUK__MKBITS(a,b,c,d,e,f,g,h) ((duk_uint8_t) ( \
30366 ((a) << 0) | ((b) << 1) | ((c) << 2) | ((d) << 3) | \
30367 ((e) << 4) | ((f) << 5) | ((g) << 6) | ((h) << 7) \
30368 ))
30369#define DUK__CHECK_BITMASK(table,cp) ((table)[(cp) >> 3] & (1 << ((cp) & 0x07)))
30370
30371/* E5.1 Section 15.1.3.3: uriReserved + uriUnescaped + '#' */
30372DUK_LOCAL const duk_uint8_t duk__encode_uriunescaped_table[16] = {
30373 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
30374 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
30375 DUK__MKBITS(0, 1, 0, 1, 1, 0, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x20-0x2f */
30376 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 0, 1, 0, 1), /* 0x30-0x3f */
30377 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */
30378 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */
30379 DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */
30380 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 1, 0), /* 0x70-0x7f */
30381};
30382
30383/* E5.1 Section 15.1.3.4: uriUnescaped */
30384DUK_LOCAL const duk_uint8_t duk__encode_uricomponent_unescaped_table[16] = {
30385 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
30386 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
30387 DUK__MKBITS(0, 1, 0, 0, 0, 0, 0, 1), DUK__MKBITS(1, 1, 1, 0, 0, 1, 1, 0), /* 0x20-0x2f */
30388 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */
30389 DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */
30390 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */
30391 DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */
30392 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 1, 0), /* 0x70-0x7f */
30393};
30394
30395/* E5.1 Section 15.1.3.1: uriReserved + '#' */
30396DUK_LOCAL const duk_uint8_t duk__decode_uri_reserved_table[16] = {
30397 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
30398 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
30399 DUK__MKBITS(0, 0, 0, 1, 1, 0, 1, 0), DUK__MKBITS(0, 0, 0, 1, 1, 0, 0, 1), /* 0x20-0x2f */
30400 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 1, 1, 0, 1, 0, 1), /* 0x30-0x3f */
30401 DUK__MKBITS(1, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x40-0x4f */
30402 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x50-0x5f */
30403 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x60-0x6f */
30404 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x70-0x7f */
30405};
30406
30407/* E5.1 Section 15.1.3.2: empty */
30408DUK_LOCAL const duk_uint8_t duk__decode_uri_component_reserved_table[16] = {
30409 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
30410 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
30411 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x20-0x2f */
30412 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */
30413 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x40-0x4f */
30414 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x50-0x5f */
30415 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x60-0x6f */
30416 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x70-0x7f */
30417};
30418
30419#if defined(DUK_USE_SECTION_B)
30420/* E5.1 Section B.2.2, step 7. */
30421DUK_LOCAL const duk_uint8_t duk__escape_unescaped_table[16] = {
30422 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x00-0x0f */
30423 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), /* 0x10-0x1f */
30424 DUK__MKBITS(0, 0, 0, 0, 0, 0, 0, 0), DUK__MKBITS(0, 0, 1, 1, 0, 1, 1, 1), /* 0x20-0x2f */
30425 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 0, 0, 0, 0, 0, 0), /* 0x30-0x3f */
30426 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x40-0x4f */
30427 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 1), /* 0x50-0x5f */
30428 DUK__MKBITS(0, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), /* 0x60-0x6f */
30429 DUK__MKBITS(1, 1, 1, 1, 1, 1, 1, 1), DUK__MKBITS(1, 1, 1, 0, 0, 0, 0, 0) /* 0x70-0x7f */
30430};
30431#endif /* DUK_USE_SECTION_B */
30432
30433typedef struct {
30434 duk_hthread *thr;
30435 duk_hstring *h_str;
30437 const duk_uint8_t *p;
30438 const duk_uint8_t *p_start;
30439 const duk_uint8_t *p_end;
30441
30442typedef void (*duk__transform_callback)(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp);
30443
30444/* XXX: refactor and share with other code */
30445DUK_LOCAL duk_small_int_t duk__decode_hex_escape(const duk_uint8_t *p, duk_small_int_t n) {
30446 duk_small_int_t ch;
30447 duk_small_int_t t = 0;
30448
30449 while (n > 0) {
30450 t = t * 16;
30451 ch = (duk_small_int_t) duk_hex_dectab[*p++];
30452 if (DUK_LIKELY(ch >= 0)) {
30453 t += ch;
30454 } else {
30455 return -1;
30456 }
30457 n--;
30458 }
30459 return t;
30460}
30461
30462DUK_LOCAL int duk__transform_helper(duk_context *ctx, duk__transform_callback callback, const void *udata) {
30463 duk_hthread *thr = (duk_hthread *) ctx;
30464 duk__transform_context tfm_ctx_alloc;
30465 duk__transform_context *tfm_ctx = &tfm_ctx_alloc;
30466 duk_codepoint_t cp;
30467
30468 tfm_ctx->thr = thr;
30469
30470 tfm_ctx->h_str = duk_to_hstring(ctx, 0);
30471 DUK_ASSERT(tfm_ctx->h_str != NULL);
30472
30473 DUK_BW_INIT_PUSHBUF(thr, &tfm_ctx->bw, DUK_HSTRING_GET_BYTELEN(tfm_ctx->h_str)); /* initial size guess */
30474
30475 tfm_ctx->p_start = DUK_HSTRING_GET_DATA(tfm_ctx->h_str);
30476 tfm_ctx->p_end = tfm_ctx->p_start + DUK_HSTRING_GET_BYTELEN(tfm_ctx->h_str);
30477 tfm_ctx->p = tfm_ctx->p_start;
30478
30479 while (tfm_ctx->p < tfm_ctx->p_end) {
30480 cp = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(thr, &tfm_ctx->p, tfm_ctx->p_start, tfm_ctx->p_end);
30481 callback(tfm_ctx, udata, cp);
30482 }
30483
30484 DUK_BW_COMPACT(thr, &tfm_ctx->bw);
30485
30486 (void) duk_buffer_to_string(ctx, -1); /* Safe if transform is safe. */
30487 return 1;
30488}
30489
30490DUK_LOCAL void duk__transform_callback_encode_uri(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
30491 duk_uint8_t xutf8_buf[DUK_UNICODE_MAX_XUTF8_LENGTH];
30492 duk_small_int_t len;
30493 duk_codepoint_t cp1, cp2;
30494 duk_small_int_t i, t;
30495 const duk_uint8_t *unescaped_table = (const duk_uint8_t *) udata;
30496
30497 /* UTF-8 encoded bytes escaped as %xx%xx%xx... -> 3 * nbytes.
30498 * Codepoint range is restricted so this is a slightly too large
30499 * but doesn't matter.
30500 */
30501 DUK_BW_ENSURE(tfm_ctx->thr, &tfm_ctx->bw, 3 * DUK_UNICODE_MAX_XUTF8_LENGTH);
30502
30503 if (cp < 0) {
30504 goto uri_error;
30505 } else if ((cp < 0x80L) && DUK__CHECK_BITMASK(unescaped_table, cp)) {
30506 DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t) cp);
30507 return;
30508 } else if (cp >= 0xdc00L && cp <= 0xdfffL) {
30509 goto uri_error;
30510 } else if (cp >= 0xd800L && cp <= 0xdbffL) {
30511 /* Needs lookahead */
30512 if (duk_unicode_decode_xutf8(tfm_ctx->thr, &tfm_ctx->p, tfm_ctx->p_start, tfm_ctx->p_end, (duk_ucodepoint_t *) &cp2) == 0) {
30513 goto uri_error;
30514 }
30515 if (!(cp2 >= 0xdc00L && cp2 <= 0xdfffL)) {
30516 goto uri_error;
30517 }
30518 cp1 = cp;
30519 cp = ((cp1 - 0xd800L) << 10) + (cp2 - 0xdc00L) + 0x10000L;
30520 } else if (cp > 0x10ffffL) {
30521 /* Although we can allow non-BMP characters (they'll decode
30522 * back into surrogate pairs), we don't allow extended UTF-8
30523 * characters; they would encode to URIs which won't decode
30524 * back because of strict UTF-8 checks in URI decoding.
30525 * (However, we could just as well allow them here.)
30526 */
30527 goto uri_error;
30528 } else {
30529 /* Non-BMP characters within valid UTF-8 range: encode as is.
30530 * They'll decode back into surrogate pairs if the escaped
30531 * output is decoded.
30532 */
30533 ;
30534 }
30535
30536 len = duk_unicode_encode_xutf8((duk_ucodepoint_t) cp, xutf8_buf);
30537 for (i = 0; i < len; i++) {
30538 t = (duk_small_int_t) xutf8_buf[i];
30539 DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr,
30540 &tfm_ctx->bw,
30541 DUK_ASC_PERCENT,
30542 (duk_uint8_t) duk_uc_nybbles[t >> 4],
30543 (duk_uint8_t) duk_uc_nybbles[t & 0x0f]);
30544 }
30545
30546 return;
30547
30548 uri_error:
30549 DUK_ERROR_URI(tfm_ctx->thr, DUK_STR_INVALID_INPUT);
30550}
30551
30552DUK_LOCAL void duk__transform_callback_decode_uri(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
30553 const duk_uint8_t *reserved_table = (const duk_uint8_t *) udata;
30554 duk_small_uint_t utf8_blen;
30555 duk_codepoint_t min_cp;
30556 duk_small_int_t t; /* must be signed */
30557 duk_small_uint_t i;
30558
30559 /* Maximum write size: XUTF8 path writes max DUK_UNICODE_MAX_XUTF8_LENGTH,
30560 * percent escape path writes max two times CESU-8 encoded BMP length.
30561 */
30562 DUK_BW_ENSURE(tfm_ctx->thr,
30563 &tfm_ctx->bw,
30564 (DUK_UNICODE_MAX_XUTF8_LENGTH >= 2 * DUK_UNICODE_MAX_CESU8_BMP_LENGTH ?
30565 DUK_UNICODE_MAX_XUTF8_LENGTH : DUK_UNICODE_MAX_CESU8_BMP_LENGTH));
30566
30567 if (cp == (duk_codepoint_t) '%') {
30568 const duk_uint8_t *p = tfm_ctx->p;
30569 duk_size_t left = (duk_size_t) (tfm_ctx->p_end - p); /* bytes left */
30570
30571 DUK_DDD(DUK_DDDPRINT("percent encoding, left=%ld", (long) left));
30572
30573 if (left < 2) {
30574 goto uri_error;
30575 }
30576
30577 t = duk__decode_hex_escape(p, 2);
30578 DUK_DDD(DUK_DDDPRINT("first byte: %ld", (long) t));
30579 if (t < 0) {
30580 goto uri_error;
30581 }
30582
30583 if (t < 0x80) {
30584 if (DUK__CHECK_BITMASK(reserved_table, t)) {
30585 /* decode '%xx' to '%xx' if decoded char in reserved set */
30586 DUK_ASSERT(tfm_ctx->p - 1 >= tfm_ctx->p_start);
30587 DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr,
30588 &tfm_ctx->bw,
30589 DUK_ASC_PERCENT,
30590 p[0],
30591 p[1]);
30592 } else {
30593 DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t) t);
30594 }
30595 tfm_ctx->p += 2;
30596 return;
30597 }
30598
30599 /* Decode UTF-8 codepoint from a sequence of hex escapes. The
30600 * first byte of the sequence has been decoded to 't'.
30601 *
30602 * Note that UTF-8 validation must be strict according to the
30603 * specification: E5.1 Section 15.1.3, decode algorithm step
30604 * 4.d.vii.8. URIError from non-shortest encodings is also
30605 * specifically noted in the spec.
30606 */
30607
30608 DUK_ASSERT(t >= 0x80);
30609 if (t < 0xc0) {
30610 /* continuation byte */
30611 goto uri_error;
30612 } else if (t < 0xe0) {
30613 /* 110x xxxx; 2 bytes */
30614 utf8_blen = 2;
30615 min_cp = 0x80L;
30616 cp = t & 0x1f;
30617 } else if (t < 0xf0) {
30618 /* 1110 xxxx; 3 bytes */
30619 utf8_blen = 3;
30620 min_cp = 0x800L;
30621 cp = t & 0x0f;
30622 } else if (t < 0xf8) {
30623 /* 1111 0xxx; 4 bytes */
30624 utf8_blen = 4;
30625 min_cp = 0x10000L;
30626 cp = t & 0x07;
30627 } else {
30628 /* extended utf-8 not allowed for URIs */
30629 goto uri_error;
30630 }
30631
30632 if (left < utf8_blen * 3 - 1) {
30633 /* '%xx%xx...%xx', p points to char after first '%' */
30634 goto uri_error;
30635 }
30636
30637 p += 3;
30638 for (i = 1; i < utf8_blen; i++) {
30639 /* p points to digit part ('%xy', p points to 'x') */
30640 t = duk__decode_hex_escape(p, 2);
30641 DUK_DDD(DUK_DDDPRINT("i=%ld utf8_blen=%ld cp=%ld t=0x%02lx",
30642 (long) i, (long) utf8_blen, (long) cp, (unsigned long) t));
30643 if (t < 0) {
30644 goto uri_error;
30645 }
30646 if ((t & 0xc0) != 0x80) {
30647 goto uri_error;
30648 }
30649 cp = (cp << 6) + (t & 0x3f);
30650 p += 3;
30651 }
30652 p--; /* p overshoots */
30653 tfm_ctx->p = p;
30654
30655 DUK_DDD(DUK_DDDPRINT("final cp=%ld, min_cp=%ld", (long) cp, (long) min_cp));
30656
30657 if (cp < min_cp || cp > 0x10ffffL || (cp >= 0xd800L && cp <= 0xdfffL)) {
30658 goto uri_error;
30659 }
30660
30661 /* The E5.1 algorithm checks whether or not a decoded codepoint
30662 * is below 0x80 and perhaps may be in the "reserved" set.
30663 * This seems pointless because the single byte UTF-8 case is
30664 * handled separately, and non-shortest encodings are rejected.
30665 * So, 'cp' cannot be below 0x80 here, and thus cannot be in
30666 * the reserved set.
30667 */
30668
30669 /* utf-8 validation ensures these */
30670 DUK_ASSERT(cp >= 0x80L && cp <= 0x10ffffL);
30671
30672 if (cp >= 0x10000L) {
30673 cp -= 0x10000L;
30674 DUK_ASSERT(cp < 0x100000L);
30675
30676 DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, ((cp >> 10) + 0xd800L));
30677 DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, ((cp & 0x03ffUL) + 0xdc00L));
30678 } else {
30679 DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp);
30680 }
30681 } else {
30682 DUK_BW_WRITE_RAW_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp);
30683 }
30684 return;
30685
30686 uri_error:
30687 DUK_ERROR_URI(tfm_ctx->thr, DUK_STR_INVALID_INPUT);
30688}
30689
30690#if defined(DUK_USE_SECTION_B)
30691DUK_LOCAL void duk__transform_callback_escape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
30692 DUK_UNREF(udata);
30693
30694 DUK_BW_ENSURE(tfm_ctx->thr, &tfm_ctx->bw, 6);
30695
30696 if (cp < 0) {
30697 goto esc_error;
30698 } else if ((cp < 0x80L) && DUK__CHECK_BITMASK(duk__escape_unescaped_table, cp)) {
30699 DUK_BW_WRITE_RAW_U8(tfm_ctx->thr, &tfm_ctx->bw, (duk_uint8_t) cp);
30700 } else if (cp < 0x100L) {
30701 DUK_BW_WRITE_RAW_U8_3(tfm_ctx->thr,
30702 &tfm_ctx->bw,
30703 (duk_uint8_t) DUK_ASC_PERCENT,
30704 (duk_uint8_t) duk_uc_nybbles[cp >> 4],
30705 (duk_uint8_t) duk_uc_nybbles[cp & 0x0f]);
30706 } else if (cp < 0x10000L) {
30707 DUK_BW_WRITE_RAW_U8_6(tfm_ctx->thr,
30708 &tfm_ctx->bw,
30709 (duk_uint8_t) DUK_ASC_PERCENT,
30710 (duk_uint8_t) DUK_ASC_LC_U,
30711 (duk_uint8_t) duk_uc_nybbles[cp >> 12],
30712 (duk_uint8_t) duk_uc_nybbles[(cp >> 8) & 0x0f],
30713 (duk_uint8_t) duk_uc_nybbles[(cp >> 4) & 0x0f],
30714 (duk_uint8_t) duk_uc_nybbles[cp & 0x0f]);
30715 } else {
30716 /* Characters outside BMP cannot be escape()'d. We could
30717 * encode them as surrogate pairs (for codepoints inside
30718 * valid UTF-8 range, but not extended UTF-8). Because
30719 * escape() and unescape() are legacy functions, we don't.
30720 */
30721 goto esc_error;
30722 }
30723
30724 return;
30725
30726 esc_error:
30727 DUK_ERROR_TYPE(tfm_ctx->thr, DUK_STR_INVALID_INPUT);
30728}
30729
30730DUK_LOCAL void duk__transform_callback_unescape(duk__transform_context *tfm_ctx, const void *udata, duk_codepoint_t cp) {
30731 duk_small_int_t t;
30732
30733 DUK_UNREF(udata);
30734
30735 if (cp == (duk_codepoint_t) '%') {
30736 const duk_uint8_t *p = tfm_ctx->p;
30737 duk_size_t left = (duk_size_t) (tfm_ctx->p_end - p); /* bytes left */
30738
30739 if (left >= 5 && p[0] == 'u' &&
30740 ((t = duk__decode_hex_escape(p + 1, 4)) >= 0)) {
30741 cp = (duk_codepoint_t) t;
30742 tfm_ctx->p += 5;
30743 } else if (left >= 2 &&
30744 ((t = duk__decode_hex_escape(p, 2)) >= 0)) {
30745 cp = (duk_codepoint_t) t;
30746 tfm_ctx->p += 2;
30747 }
30748 }
30749
30750 DUK_BW_WRITE_ENSURE_XUTF8(tfm_ctx->thr, &tfm_ctx->bw, cp);
30751}
30752#endif /* DUK_USE_SECTION_B */
30753
30754/*
30755 * Eval
30756 *
30757 * Eval needs to handle both a "direct eval" and an "indirect eval".
30758 * Direct eval handling needs access to the caller's activation so that its
30759 * lexical environment can be accessed. A direct eval is only possible from
30760 * Ecmascript code; an indirect eval call is possible also from C code.
30761 * When an indirect eval call is made from C code, there may not be a
30762 * calling activation at all which needs careful handling.
30763 */
30764
30765DUK_INTERNAL duk_ret_t duk_bi_global_object_eval(duk_context *ctx) {
30766 duk_hthread *thr = (duk_hthread *) ctx;
30767 duk_hstring *h;
30768 duk_activation *act_caller;
30769 duk_activation *act_eval;
30770 duk_activation *act;
30771 duk_hcompfunc *func;
30772 duk_hobject *outer_lex_env;
30773 duk_hobject *outer_var_env;
30774 duk_bool_t this_to_global = 1;
30775 duk_small_uint_t comp_flags;
30776 duk_int_t level = -2;
30777
30778 DUK_ASSERT(duk_get_top(ctx) == 1 || duk_get_top(ctx) == 2); /* 2 when called by debugger */
30779 DUK_ASSERT(thr->callstack_top >= 1); /* at least this function exists */
30780 DUK_ASSERT(((thr->callstack + thr->callstack_top - 1)->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0 || /* indirect eval */
30781 (thr->callstack_top >= 2)); /* if direct eval, calling activation must exist */
30782
30783 /*
30784 * callstack_top - 1 --> this function
30785 * callstack_top - 2 --> caller (may not exist)
30786 *
30787 * If called directly from C, callstack_top might be 1. If calling
30788 * activation doesn't exist, call must be indirect.
30789 */
30790
30791 h = duk_get_hstring_notsymbol(ctx, 0);
30792 if (!h) {
30793 /* Symbol must be returned as is, like any non-string values. */
30794 return 1; /* return arg as-is */
30795 }
30796
30797#if defined(DUK_USE_DEBUGGER_SUPPORT)
30798 /* NOTE: level is used only by the debugger and should never be present
30799 * for an Ecmascript eval().
30800 */
30801 DUK_ASSERT(level == -2); /* by default, use caller's environment */
30802 if (duk_get_top(ctx) >= 2 && duk_is_number(ctx, 1)) {
30803 level = duk_get_int(ctx, 1);
30804 }
30805 DUK_ASSERT(level <= -2); /* This is guaranteed by debugger code. */
30806#endif
30807
30808 /* [ source ] */
30809
30810 comp_flags = DUK_JS_COMPILE_FLAG_EVAL;
30811 act_eval = thr->callstack + thr->callstack_top - 1; /* this function */
30812 if (thr->callstack_top >= (duk_size_t) -level) {
30813 /* Have a calling activation, check for direct eval (otherwise
30814 * assume indirect eval.
30815 */
30816 act_caller = thr->callstack + thr->callstack_top + level; /* caller */
30817 if ((act_caller->flags & DUK_ACT_FLAG_STRICT) &&
30818 (act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL)) {
30819 /* Only direct eval inherits strictness from calling code
30820 * (E5.1 Section 10.1.1).
30821 */
30822 comp_flags |= DUK_JS_COMPILE_FLAG_STRICT;
30823 }
30824 } else {
30825 DUK_ASSERT((act_eval->flags & DUK_ACT_FLAG_DIRECT_EVAL) == 0);
30826 }
30827 act_caller = NULL; /* avoid dereference after potential callstack realloc */
30828 act_eval = NULL;
30829
30830 duk_push_hstring_stridx(ctx, DUK_STRIDX_INPUT); /* XXX: copy from caller? */
30831 duk_js_compile(thr,
30832 (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h),
30833 (duk_size_t) DUK_HSTRING_GET_BYTELEN(h),
30834 comp_flags);
30835 func = (duk_hcompfunc *) duk_known_hobject(ctx, -1);
30836 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) func));
30837
30838 /* [ source template ] */
30839
30840 /* E5 Section 10.4.2 */
30841 DUK_ASSERT(thr->callstack_top >= 1);
30842 act = thr->callstack + thr->callstack_top - 1; /* this function */
30843 if (act->flags & DUK_ACT_FLAG_DIRECT_EVAL) {
30844 DUK_ASSERT(thr->callstack_top >= 2);
30845 act = thr->callstack + thr->callstack_top + level; /* caller */
30846 if (act->lex_env == NULL) {
30847 DUK_ASSERT(act->var_env == NULL);
30848 DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
30849
30850 /* this may have side effects, so re-lookup act */
30851 duk_js_init_activation_environment_records_delayed(thr, act);
30852 act = thr->callstack + thr->callstack_top + level;
30853 }
30854 DUK_ASSERT(act->lex_env != NULL);
30855 DUK_ASSERT(act->var_env != NULL);
30856
30857 this_to_global = 0;
30858
30859 if (DUK_HOBJECT_HAS_STRICT((duk_hobject *) func)) {
30860 duk_hobject *new_env;
30861 duk_hobject *act_lex_env;
30862
30863 DUK_DDD(DUK_DDDPRINT("direct eval call to a strict function -> "
30864 "var_env and lex_env to a fresh env, "
30865 "this_binding to caller's this_binding"));
30866
30867 act = thr->callstack + thr->callstack_top + level; /* caller */
30868 act_lex_env = act->lex_env;
30869 act = NULL; /* invalidated */
30870
30871 new_env = duk_push_object_helper_proto(ctx,
30872 DUK_HOBJECT_FLAG_EXTENSIBLE |
30873 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
30874 act_lex_env);
30875 DUK_ASSERT(new_env != NULL);
30876 DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO", (duk_heaphdr *) new_env));
30877
30878 outer_lex_env = new_env;
30879 outer_var_env = new_env;
30880
30881 duk_insert(ctx, 0); /* stash to bottom of value stack to keep new_env reachable for duration of eval */
30882
30883 /* compiler's responsibility */
30884 DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV((duk_hobject *) func));
30885 } else {
30886 DUK_DDD(DUK_DDDPRINT("direct eval call to a non-strict function -> "
30887 "var_env and lex_env to caller's envs, "
30888 "this_binding to caller's this_binding"));
30889
30890 outer_lex_env = act->lex_env;
30891 outer_var_env = act->var_env;
30892
30893 /* compiler's responsibility */
30894 DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV((duk_hobject *) func));
30895 }
30896 } else {
30897 DUK_DDD(DUK_DDDPRINT("indirect eval call -> var_env and lex_env to "
30898 "global object, this_binding to global object"));
30899
30900 this_to_global = 1;
30901 outer_lex_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
30902 outer_var_env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
30903 }
30904 act = NULL;
30905
30906 /* Eval code doesn't need an automatic .prototype object. */
30907 duk_js_push_closure(thr, func, outer_var_env, outer_lex_env, 0 /*add_auto_proto*/);
30908
30909 /* [ source template closure ] */
30910
30911 if (this_to_global) {
30912 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
30913 duk_push_hobject_bidx(ctx, DUK_BIDX_GLOBAL);
30914 } else {
30915 duk_tval *tv;
30916 DUK_ASSERT(thr->callstack_top >= 2);
30917 act = thr->callstack + thr->callstack_top + level; /* caller */
30918 tv = thr->valstack + act->idx_bottom - 1; /* this is just beneath bottom */
30919 DUK_ASSERT(tv >= thr->valstack);
30920 duk_push_tval(ctx, tv);
30921 }
30922
30923 DUK_DDD(DUK_DDDPRINT("eval -> lex_env=%!iO, var_env=%!iO, this_binding=%!T",
30924 (duk_heaphdr *) outer_lex_env,
30925 (duk_heaphdr *) outer_var_env,
30926 duk_get_tval(ctx, -1)));
30927
30928 /* [ source template closure this ] */
30929
30930 duk_call_method(ctx, 0);
30931
30932 /* [ source template result ] */
30933
30934 return 1;
30935}
30936
30937/*
30938 * Parsing of ints and floats
30939 */
30940
30941#if defined(DUK_USE_GLOBAL_BUILTIN)
30942DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_int(duk_context *ctx) {
30943 duk_int32_t radix;
30944 duk_small_uint_t s2n_flags;
30945
30946 DUK_ASSERT_TOP(ctx, 2);
30947 duk_to_string(ctx, 0); /* Reject symbols. */
30948
30949 radix = duk_to_int32(ctx, 1);
30950
30951 /* While parseInt() recognizes 0xdeadbeef, it doesn't recognize
30952 * ES2015 0o123 or 0b10001.
30953 */
30954 s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
30955 DUK_S2N_FLAG_ALLOW_GARBAGE |
30956 DUK_S2N_FLAG_ALLOW_PLUS |
30957 DUK_S2N_FLAG_ALLOW_MINUS |
30958 DUK_S2N_FLAG_ALLOW_LEADING_ZERO |
30959 DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT;
30960
30961 /* Specification stripPrefix maps to DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT.
30962 *
30963 * Don't autodetect octals (from leading zeroes), require user code to
30964 * provide an explicit radix 8 for parsing octal. See write-up from Mozilla:
30965 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt#ECMAScript_5_Removes_Octal_Interpretation
30966 */
30967
30968 if (radix != 0) {
30969 if (radix < 2 || radix > 36) {
30970 goto ret_nan;
30971 }
30972 if (radix != 16) {
30973 s2n_flags &= ~DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT;
30974 }
30975 } else {
30976 radix = 10;
30977 }
30978
30979 duk_dup_0(ctx);
30980 duk_numconv_parse(ctx, radix, s2n_flags);
30981 return 1;
30982
30983 ret_nan:
30984 duk_push_nan(ctx);
30985 return 1;
30986}
30987#endif /* DUK_USE_GLOBAL_BUILTIN */
30988
30989#if defined(DUK_USE_GLOBAL_BUILTIN)
30990DUK_INTERNAL duk_ret_t duk_bi_global_object_parse_float(duk_context *ctx) {
30991 duk_small_uint_t s2n_flags;
30992 duk_int32_t radix;
30993
30994 DUK_ASSERT_TOP(ctx, 1);
30995 duk_to_string(ctx, 0); /* Reject symbols. */
30996
30997 radix = 10;
30998
30999 /* XXX: check flags */
31000 s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
31001 DUK_S2N_FLAG_ALLOW_EXP |
31002 DUK_S2N_FLAG_ALLOW_GARBAGE |
31003 DUK_S2N_FLAG_ALLOW_PLUS |
31004 DUK_S2N_FLAG_ALLOW_MINUS |
31005 DUK_S2N_FLAG_ALLOW_INF |
31006 DUK_S2N_FLAG_ALLOW_FRAC |
31007 DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
31008 DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
31009 DUK_S2N_FLAG_ALLOW_LEADING_ZERO;
31010
31011 duk_numconv_parse(ctx, radix, s2n_flags);
31012 return 1;
31013}
31014#endif /* DUK_USE_GLOBAL_BUILTIN */
31015
31016/*
31017 * Number checkers
31018 */
31019
31020#if defined(DUK_USE_GLOBAL_BUILTIN)
31021DUK_INTERNAL duk_ret_t duk_bi_global_object_is_nan(duk_context *ctx) {
31022 duk_double_t d = duk_to_number(ctx, 0);
31023 duk_push_boolean(ctx, DUK_ISNAN(d));
31024 return 1;
31025}
31026#endif /* DUK_USE_GLOBAL_BUILTIN */
31027
31028#if defined(DUK_USE_GLOBAL_BUILTIN)
31029DUK_INTERNAL duk_ret_t duk_bi_global_object_is_finite(duk_context *ctx) {
31030 duk_double_t d = duk_to_number(ctx, 0);
31031 duk_push_boolean(ctx, DUK_ISFINITE(d));
31032 return 1;
31033}
31034#endif /* DUK_USE_GLOBAL_BUILTIN */
31035
31036/*
31037 * URI handling
31038 */
31039
31040#if defined(DUK_USE_GLOBAL_BUILTIN)
31041DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri(duk_context *ctx) {
31042 return duk__transform_helper(ctx, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_reserved_table);
31043}
31044
31045DUK_INTERNAL duk_ret_t duk_bi_global_object_decode_uri_component(duk_context *ctx) {
31046 return duk__transform_helper(ctx, duk__transform_callback_decode_uri, (const void *) duk__decode_uri_component_reserved_table);
31047}
31048
31049DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri(duk_context *ctx) {
31050 return duk__transform_helper(ctx, duk__transform_callback_encode_uri, (const void *) duk__encode_uriunescaped_table);
31051}
31052
31053DUK_INTERNAL duk_ret_t duk_bi_global_object_encode_uri_component(duk_context *ctx) {
31054 return duk__transform_helper(ctx, duk__transform_callback_encode_uri, (const void *) duk__encode_uricomponent_unescaped_table);
31055}
31056
31057#if defined(DUK_USE_SECTION_B)
31058DUK_INTERNAL duk_ret_t duk_bi_global_object_escape(duk_context *ctx) {
31059 return duk__transform_helper(ctx, duk__transform_callback_escape, (const void *) NULL);
31060}
31061
31062DUK_INTERNAL duk_ret_t duk_bi_global_object_unescape(duk_context *ctx) {
31063 return duk__transform_helper(ctx, duk__transform_callback_unescape, (const void *) NULL);
31064}
31065#endif /* DUK_USE_SECTION_B */
31066#endif /* DUK_USE_GLOBAL_BUILTIN */
31067
31068/* automatic undefs */
31069#undef DUK__CHECK_BITMASK
31070#undef DUK__MKBITS
31071/*
31072 * JSON built-ins.
31073 *
31074 * See doc/json.rst.
31075 *
31076 * Codepoints are handled as duk_uint_fast32_t to ensure that the full
31077 * unsigned 32-bit range is supported. This matters to e.g. JX.
31078 *
31079 * Input parsing doesn't do an explicit end-of-input check at all. This is
31080 * safe: input string data is always NUL-terminated (0x00) and valid JSON
31081 * inputs never contain plain NUL characters, so that as long as syntax checks
31082 * are correct, we'll never read past the NUL. This approach reduces code size
31083 * and improves parsing performance, but it's critical that syntax checks are
31084 * indeed correct!
31085 */
31086
31087/* #include duk_internal.h -> already included */
31088
31089#if defined(DUK_USE_JSON_SUPPORT)
31090
31091/*
31092 * Local defines and forward declarations.
31093 */
31094
31095#define DUK__JSON_DECSTR_BUFSIZE 128
31096#define DUK__JSON_DECSTR_CHUNKSIZE 64
31097#define DUK__JSON_ENCSTR_CHUNKSIZE 64
31098#define DUK__JSON_STRINGIFY_BUFSIZE 128
31099#define DUK__JSON_MAX_ESC_LEN 10 /* '\Udeadbeef' */
31100
31101DUK_LOCAL_DECL void duk__dec_syntax_error(duk_json_dec_ctx *js_ctx);
31102DUK_LOCAL_DECL void duk__dec_eat_white(duk_json_dec_ctx *js_ctx);
31103#if defined(DUK_USE_JX)
31104DUK_LOCAL_DECL duk_uint8_t duk__dec_peek(duk_json_dec_ctx *js_ctx);
31105#endif
31106DUK_LOCAL_DECL duk_uint8_t duk__dec_get(duk_json_dec_ctx *js_ctx);
31107DUK_LOCAL_DECL duk_uint8_t duk__dec_get_nonwhite(duk_json_dec_ctx *js_ctx);
31108DUK_LOCAL_DECL duk_uint_fast32_t duk__dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, duk_small_uint_t n);
31109DUK_LOCAL_DECL void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t stridx);
31110DUK_LOCAL_DECL void duk__dec_string(duk_json_dec_ctx *js_ctx);
31111#if defined(DUK_USE_JX)
31112DUK_LOCAL_DECL void duk__dec_plain_string(duk_json_dec_ctx *js_ctx);
31113DUK_LOCAL_DECL void duk__dec_pointer(duk_json_dec_ctx *js_ctx);
31114DUK_LOCAL_DECL void duk__dec_buffer(duk_json_dec_ctx *js_ctx);
31115#endif
31116DUK_LOCAL_DECL void duk__dec_number(duk_json_dec_ctx *js_ctx);
31117DUK_LOCAL_DECL void duk__dec_objarr_entry(duk_json_dec_ctx *js_ctx);
31118DUK_LOCAL_DECL void duk__dec_objarr_exit(duk_json_dec_ctx *js_ctx);
31119DUK_LOCAL_DECL void duk__dec_object(duk_json_dec_ctx *js_ctx);
31120DUK_LOCAL_DECL void duk__dec_array(duk_json_dec_ctx *js_ctx);
31121DUK_LOCAL_DECL void duk__dec_value(duk_json_dec_ctx *js_ctx);
31122DUK_LOCAL_DECL void duk__dec_reviver_walk(duk_json_dec_ctx *js_ctx);
31123
31124DUK_LOCAL_DECL void duk__emit_1(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch);
31125DUK_LOCAL_DECL void duk__emit_2(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch1, duk_uint_fast8_t ch2);
31126DUK_LOCAL_DECL void duk__unemit_1(duk_json_enc_ctx *js_ctx);
31127DUK_LOCAL_DECL void duk__emit_hstring(duk_json_enc_ctx *js_ctx, duk_hstring *h);
31128#if defined(DUK_USE_FASTINT)
31129DUK_LOCAL_DECL void duk__emit_cstring(duk_json_enc_ctx *js_ctx, const char *p);
31130#endif
31131DUK_LOCAL_DECL void duk__emit_stridx(duk_json_enc_ctx *js_ctx, duk_small_uint_t stridx);
31132DUK_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);
31133DUK_LOCAL_DECL void duk__enc_key_autoquote(duk_json_enc_ctx *js_ctx, duk_hstring *k);
31134DUK_LOCAL_DECL void duk__enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_str);
31135DUK_LOCAL_DECL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top);
31136DUK_LOCAL_DECL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top);
31137DUK_LOCAL_DECL void duk__enc_object(duk_json_enc_ctx *js_ctx);
31138DUK_LOCAL_DECL void duk__enc_array(duk_json_enc_ctx *js_ctx);
31139DUK_LOCAL_DECL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder);
31140DUK_LOCAL_DECL duk_bool_t duk__enc_allow_into_proplist(duk_tval *tv);
31141DUK_LOCAL_DECL void duk__enc_double(duk_json_enc_ctx *js_ctx);
31142#if defined(DUK_USE_FASTINT)
31143DUK_LOCAL_DECL void duk__enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv);
31144#endif
31145#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
31146DUK_LOCAL_DECL void duk__enc_buffer(duk_json_enc_ctx *js_ctx, duk_hbuffer *h);
31147DUK_LOCAL_DECL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr);
31148#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
31149DUK_LOCAL_DECL void duk__enc_bufobj(duk_json_enc_ctx *js_ctx, duk_hbufobj *h_bufobj);
31150#endif
31151#endif
31152DUK_LOCAL_DECL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth);
31153
31154/*
31155 * Helper tables
31156 */
31157
31158#if defined(DUK_USE_JSON_QUOTESTRING_FASTPATH)
31159DUK_LOCAL const duk_uint8_t duk__json_quotestr_lookup[256] = {
31160 /* 0x00 ... 0x7f: as is
31161 * 0x80: escape generically
31162 * 0x81: slow path
31163 * 0xa0 ... 0xff: backslash + one char
31164 */
31165
31166 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xe2, 0xf4, 0xee, 0x80, 0xe6, 0xf2, 0x80, 0x80,
31167 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
31168 0x20, 0x21, 0xa2, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
31169 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
31170 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
31171 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0xdc, 0x5d, 0x5e, 0x5f,
31172 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
31173 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x81,
31174 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
31175 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
31176 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
31177 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
31178 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
31179 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
31180 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
31181 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81
31182};
31183#else /* DUK_USE_JSON_QUOTESTRING_FASTPATH */
31184DUK_LOCAL const duk_uint8_t duk__json_quotestr_esc[14] = {
31185 DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL,
31186 DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL, DUK_ASC_NUL,
31187 DUK_ASC_LC_B, DUK_ASC_LC_T, DUK_ASC_LC_N, DUK_ASC_NUL,
31188 DUK_ASC_LC_F, DUK_ASC_LC_R
31189};
31190#endif /* DUK_USE_JSON_QUOTESTRING_FASTPATH */
31191
31192#if defined(DUK_USE_JSON_DECSTRING_FASTPATH)
31193DUK_LOCAL const duk_uint8_t duk__json_decstr_lookup[256] = {
31194 /* 0x00: slow path
31195 * other: as is
31196 */
31197 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31198 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31199 0x20, 0x21, 0x00, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
31200 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
31201 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
31202 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x00, 0x5d, 0x5e, 0x5f,
31203 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
31204 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
31205 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
31206 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
31207 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
31208 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
31209 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
31210 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
31211 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
31212 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
31213};
31214#endif /* DUK_USE_JSON_DECSTRING_FASTPATH */
31215
31216#if defined(DUK_USE_JSON_EATWHITE_FASTPATH)
31217DUK_LOCAL const duk_uint8_t duk__json_eatwhite_lookup[256] = {
31218 /* 0x00: finish (non-white)
31219 * 0x01: continue
31220 */
31221 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
31222 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31223 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31224 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31225 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31226 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31227 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31228 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31229 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31230 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31231 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31232 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31233 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31234 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31235 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31236 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
31237};
31238#endif /* DUK_USE_JSON_EATWHITE_FASTPATH */
31239
31240#if defined(DUK_USE_JSON_DECNUMBER_FASTPATH)
31241DUK_LOCAL const duk_uint8_t duk__json_decnumber_lookup[256] = {
31242 /* 0x00: finish (not part of number)
31243 * 0x01: continue
31244 */
31245 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31246 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31247 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00,
31248 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31249 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31250 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31251 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31252 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31253 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31254 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31255 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31256 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31257 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31258 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31259 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
31260 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
31261};
31262#endif /* DUK_USE_JSON_DECNUMBER_FASTPATH */
31263
31264/*
31265 * Parsing implementation.
31266 *
31267 * JSON lexer is now separate from duk_lexer.c because there are numerous
31268 * small differences making it difficult to share the lexer.
31269 *
31270 * The parser here works with raw bytes directly; this works because all
31271 * JSON delimiters are ASCII characters. Invalid xUTF-8 encoded values
31272 * inside strings will be passed on without normalization; this is not a
31273 * compliance concern because compliant inputs will always be valid
31274 * CESU-8 encodings.
31275 */
31276
31277DUK_LOCAL void duk__dec_syntax_error(duk_json_dec_ctx *js_ctx) {
31278 /* Shared handler to minimize parser size. Cause will be
31279 * hidden, unfortunately, but we'll have an offset which
31280 * is often quite enough.
31281 */
31282 DUK_ERROR_FMT1(js_ctx->thr, DUK_ERR_SYNTAX_ERROR, DUK_STR_FMT_INVALID_JSON,
31283 (long) (js_ctx->p - js_ctx->p_start));
31284}
31285
31286DUK_LOCAL void duk__dec_eat_white(duk_json_dec_ctx *js_ctx) {
31287 const duk_uint8_t *p;
31288 duk_uint8_t t;
31289
31290 p = js_ctx->p;
31291 for (;;) {
31292 DUK_ASSERT(p <= js_ctx->p_end);
31293 t = *p;
31294
31295#if defined(DUK_USE_JSON_EATWHITE_FASTPATH)
31296 /* This fast path is pretty marginal in practice.
31297 * XXX: candidate for removal.
31298 */
31299 DUK_ASSERT(duk__json_eatwhite_lookup[0x00] == 0x00); /* end-of-input breaks */
31300 if (duk__json_eatwhite_lookup[t] == 0) {
31301 break;
31302 }
31303#else /* DUK_USE_JSON_EATWHITE_FASTPATH */
31304 if (!(t == 0x20 || t == 0x0a || t == 0x0d || t == 0x09)) {
31305 /* NUL also comes here. Comparison order matters, 0x20
31306 * is most common whitespace.
31307 */
31308 break;
31309 }
31310#endif /* DUK_USE_JSON_EATWHITE_FASTPATH */
31311 p++;
31312 }
31313 js_ctx->p = p;
31314}
31315
31316#if defined(DUK_USE_JX)
31317DUK_LOCAL duk_uint8_t duk__dec_peek(duk_json_dec_ctx *js_ctx) {
31318 DUK_ASSERT(js_ctx->p <= js_ctx->p_end);
31319 return *js_ctx->p;
31320}
31321#endif
31322
31323DUK_LOCAL duk_uint8_t duk__dec_get(duk_json_dec_ctx *js_ctx) {
31324 DUK_ASSERT(js_ctx->p <= js_ctx->p_end);
31325 return *js_ctx->p++;
31326}
31327
31328DUK_LOCAL duk_uint8_t duk__dec_get_nonwhite(duk_json_dec_ctx *js_ctx) {
31329 duk__dec_eat_white(js_ctx);
31330 return duk__dec_get(js_ctx);
31331}
31332
31333/* For JX, expressing the whole unsigned 32-bit range matters. */
31334DUK_LOCAL duk_uint_fast32_t duk__dec_decode_hex_escape(duk_json_dec_ctx *js_ctx, duk_small_uint_t n) {
31335 duk_small_uint_t i;
31336 duk_uint_fast32_t res = 0;
31337 duk_uint8_t x;
31338 duk_small_int_t t;
31339
31340 for (i = 0; i < n; i++) {
31341 /* XXX: share helper from lexer; duk_lexer.c / hexval(). */
31342
31343 x = duk__dec_get(js_ctx);
31344 DUK_DDD(DUK_DDDPRINT("decode_hex_escape: i=%ld, n=%ld, res=%ld, x=%ld",
31345 (long) i, (long) n, (long) res, (long) x));
31346
31347 /* x == 0x00 (EOF) causes syntax_error */
31348 DUK_ASSERT(duk_hex_dectab[0] == -1);
31349 t = duk_hex_dectab[x & 0xff];
31350 if (DUK_LIKELY(t >= 0)) {
31351 res = (res * 16) + t;
31352 } else {
31353 /* catches EOF and invalid digits */
31354 goto syntax_error;
31355 }
31356 }
31357
31358 DUK_DDD(DUK_DDDPRINT("final hex decoded value: %ld", (long) res));
31359 return res;
31360
31361 syntax_error:
31362 duk__dec_syntax_error(js_ctx);
31363 DUK_UNREACHABLE();
31364 return 0;
31365}
31366
31367DUK_LOCAL void duk__dec_req_stridx(duk_json_dec_ctx *js_ctx, duk_small_uint_t stridx) {
31368 duk_hstring *h;
31369 const duk_uint8_t *p;
31370 duk_uint8_t x, y;
31371
31372 /* First character has already been eaten and checked by the caller.
31373 * We can scan until a NUL in stridx string because no built-in strings
31374 * have internal NULs.
31375 */
31376
31377 DUK_ASSERT_STRIDX_VALID(stridx);
31378 h = DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx);
31379 DUK_ASSERT(h != NULL);
31380
31381 p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h) + 1;
31382 DUK_ASSERT(*(js_ctx->p - 1) == *(p - 1)); /* first character has been matched */
31383
31384 for (;;) {
31385 x = *p;
31386 if (x == 0) {
31387 break;
31388 }
31389 y = duk__dec_get(js_ctx);
31390 if (x != y) {
31391 /* Catches EOF of JSON input. */
31392 goto syntax_error;
31393 }
31394 p++;
31395 }
31396
31397 return;
31398
31399 syntax_error:
31400 duk__dec_syntax_error(js_ctx);
31401 DUK_UNREACHABLE();
31402}
31403
31404DUK_LOCAL duk_small_int_t duk__dec_string_escape(duk_json_dec_ctx *js_ctx, duk_uint8_t **ext_p) {
31405 duk_uint_fast32_t cp;
31406
31407 /* EOF (-1) will be cast to an unsigned value first
31408 * and then re-cast for the switch. In any case, it
31409 * will match the default case (syntax error).
31410 */
31411 cp = (duk_uint_fast32_t) duk__dec_get(js_ctx);
31412 switch (cp) {
31413 case DUK_ASC_BACKSLASH: break;
31414 case DUK_ASC_DOUBLEQUOTE: break;
31415 case DUK_ASC_SLASH: break;
31416 case DUK_ASC_LC_T: cp = 0x09; break;
31417 case DUK_ASC_LC_N: cp = 0x0a; break;
31418 case DUK_ASC_LC_R: cp = 0x0d; break;
31419 case DUK_ASC_LC_F: cp = 0x0c; break;
31420 case DUK_ASC_LC_B: cp = 0x08; break;
31421 case DUK_ASC_LC_U: {
31422 cp = duk__dec_decode_hex_escape(js_ctx, 4);
31423 break;
31424 }
31425#if defined(DUK_USE_JX)
31426 case DUK_ASC_UC_U: {
31427 if (js_ctx->flag_ext_custom) {
31428 cp = duk__dec_decode_hex_escape(js_ctx, 8);
31429 } else {
31430 return 1; /* syntax error */
31431 }
31432 break;
31433 }
31434 case DUK_ASC_LC_X: {
31435 if (js_ctx->flag_ext_custom) {
31436 cp = duk__dec_decode_hex_escape(js_ctx, 2);
31437 } else {
31438 return 1; /* syntax error */
31439 }
31440 break;
31441 }
31442#endif /* DUK_USE_JX */
31443 default:
31444 /* catches EOF (0x00) */
31445 return 1; /* syntax error */
31446 }
31447
31448 DUK_RAW_WRITE_XUTF8(*ext_p, cp);
31449
31450 return 0;
31451}
31452
31453DUK_LOCAL void duk__dec_string(duk_json_dec_ctx *js_ctx) {
31454 duk_hthread *thr = js_ctx->thr;
31455 duk_context *ctx = (duk_context *) thr;
31456 duk_bufwriter_ctx bw_alloc;
31458 duk_uint8_t *q;
31459
31460 /* '"' was eaten by caller */
31461
31462 /* Note that we currently parse -bytes-, not codepoints.
31463 * All non-ASCII extended UTF-8 will encode to bytes >= 0x80,
31464 * so they'll simply pass through (valid UTF-8 or not).
31465 */
31466
31467 bw = &bw_alloc;
31468 DUK_BW_INIT_PUSHBUF(js_ctx->thr, bw, DUK__JSON_DECSTR_BUFSIZE);
31469 q = DUK_BW_GET_PTR(js_ctx->thr, bw);
31470
31471#if defined(DUK_USE_JSON_DECSTRING_FASTPATH)
31472 for (;;) {
31473 duk_small_uint_t safe;
31474 duk_uint8_t b, x;
31475 const duk_uint8_t *p;
31476
31477 /* Select a safe loop count where no output checks are
31478 * needed assuming we won't encounter escapes. Input
31479 * bound checks are not necessary as a NUL (guaranteed)
31480 * will cause a SyntaxError before we read out of bounds.
31481 */
31482
31483 safe = DUK__JSON_DECSTR_CHUNKSIZE;
31484
31485 /* Ensure space for 1:1 output plus one escape. */
31486 q = DUK_BW_ENSURE_RAW(js_ctx->thr, bw, safe + DUK_UNICODE_MAX_XUTF8_LENGTH, q);
31487
31488 p = js_ctx->p; /* temp copy, write back for next loop */
31489 for (;;) {
31490 if (safe == 0) {
31491 js_ctx->p = p;
31492 break;
31493 }
31494 safe--;
31495
31496 /* End of input (NUL) goes through slow path and causes SyntaxError. */
31497 DUK_ASSERT(duk__json_decstr_lookup[0] == 0x00);
31498
31499 b = *p++;
31500 x = (duk_small_int_t) duk__json_decstr_lookup[b];
31501 if (DUK_LIKELY(x != 0)) {
31502 /* Fast path, decode as is. */
31503 *q++ = b;
31504 } else if (b == DUK_ASC_DOUBLEQUOTE) {
31505 js_ctx->p = p;
31506 goto found_quote;
31507 } else if (b == DUK_ASC_BACKSLASH) {
31508 /* We've ensured space for one escaped input; then
31509 * bail out and recheck (this makes escape handling
31510 * quite slow but it's uncommon).
31511 */
31512 js_ctx->p = p;
31513 if (duk__dec_string_escape(js_ctx, &q) != 0) {
31514 goto syntax_error;
31515 }
31516 break;
31517 } else {
31518 js_ctx->p = p;
31519 goto syntax_error;
31520 }
31521 }
31522 }
31523 found_quote:
31524#else /* DUK_USE_JSON_DECSTRING_FASTPATH */
31525 for (;;) {
31526 duk_uint8_t x;
31527
31528 q = DUK_BW_ENSURE_RAW(js_ctx->thr, bw, DUK_UNICODE_MAX_XUTF8_LENGTH, q);
31529
31530 x = duk__dec_get(js_ctx);
31531
31532 if (x == DUK_ASC_DOUBLEQUOTE) {
31533 break;
31534 } else if (x == DUK_ASC_BACKSLASH) {
31535 if (duk__dec_string_escape(js_ctx, &q) != 0) {
31536 goto syntax_error;
31537 }
31538 } else if (x < 0x20) {
31539 /* catches EOF (NUL) */
31540 goto syntax_error;
31541 } else {
31542 *q++ = (duk_uint8_t) x;
31543 }
31544 }
31545#endif /* DUK_USE_JSON_DECSTRING_FASTPATH */
31546
31547 DUK_BW_SETPTR_AND_COMPACT(js_ctx->thr, bw, q);
31548 (void) duk_buffer_to_string(ctx, -1); /* Safe if input string is safe. */
31549
31550 /* [ ... str ] */
31551
31552 return;
31553
31554 syntax_error:
31555 duk__dec_syntax_error(js_ctx);
31556 DUK_UNREACHABLE();
31557}
31558
31559#if defined(DUK_USE_JX)
31560/* Decode a plain string consisting entirely of identifier characters.
31561 * Used to parse plain keys (e.g. "foo: 123").
31562 */
31563DUK_LOCAL void duk__dec_plain_string(duk_json_dec_ctx *js_ctx) {
31564 duk_hthread *thr = js_ctx->thr;
31565 duk_context *ctx = (duk_context *) thr;
31566 const duk_uint8_t *p;
31567 duk_small_int_t x;
31568
31569 /* Caller has already eaten the first char so backtrack one byte. */
31570
31571 js_ctx->p--; /* safe */
31572 p = js_ctx->p;
31573
31574 /* Here again we parse bytes, and non-ASCII UTF-8 will cause end of
31575 * parsing (which is correct except if there are non-shortest encodings).
31576 * There is also no need to check explicitly for end of input buffer as
31577 * the input is NUL padded and NUL will exit the parsing loop.
31578 *
31579 * Because no unescaping takes place, we can just scan to the end of the
31580 * plain string and intern from the input buffer.
31581 */
31582
31583 for (;;) {
31584 x = *p;
31585
31586 /* There is no need to check the first character specially here
31587 * (i.e. reject digits): the caller only accepts valid initial
31588 * characters and won't call us if the first character is a digit.
31589 * This also ensures that the plain string won't be empty.
31590 */
31591
31592 if (!duk_unicode_is_identifier_part((duk_codepoint_t) x)) {
31593 break;
31594 }
31595 p++;
31596 }
31597
31598 duk_push_lstring(ctx, (const char *) js_ctx->p, (duk_size_t) (p - js_ctx->p));
31599 js_ctx->p = p;
31600
31601 /* [ ... str ] */
31602}
31603#endif /* DUK_USE_JX */
31604
31605#if defined(DUK_USE_JX)
31606DUK_LOCAL void duk__dec_pointer(duk_json_dec_ctx *js_ctx) {
31607 duk_hthread *thr = js_ctx->thr;
31608 duk_context *ctx = (duk_context *) thr;
31609 const duk_uint8_t *p;
31610 duk_small_int_t x;
31611 void *voidptr;
31612
31613 /* Caller has already eaten the first character ('(') which we don't need. */
31614
31615 p = js_ctx->p;
31616
31617 for (;;) {
31618 x = *p;
31619
31620 /* Assume that the native representation never contains a closing
31621 * parenthesis.
31622 */
31623
31624 if (x == DUK_ASC_RPAREN) {
31625 break;
31626 } else if (x <= 0) {
31627 /* NUL term or -1 (EOF), NUL check would suffice */
31628 goto syntax_error;
31629 }
31630 p++;
31631 }
31632
31633 /* There is no need to NUL delimit the sscanf() call: trailing garbage is
31634 * ignored and there is always a NUL terminator which will force an error
31635 * if no error is encountered before it. It's possible that the scan
31636 * would scan further than between [js_ctx->p,p[ though and we'd advance
31637 * by less than the scanned value.
31638 *
31639 * Because pointers are platform specific, a failure to scan a pointer
31640 * results in a null pointer which is a better placeholder than a missing
31641 * value or an error.
31642 */
31643
31644 voidptr = NULL;
31645 (void) DUK_SSCANF((const char *) js_ctx->p, DUK_STR_FMT_PTR, &voidptr);
31646 duk_push_pointer(ctx, voidptr);
31647 js_ctx->p = p + 1; /* skip ')' */
31648
31649 /* [ ... ptr ] */
31650
31651 return;
31652
31653 syntax_error:
31654 duk__dec_syntax_error(js_ctx);
31655 DUK_UNREACHABLE();
31656}
31657#endif /* DUK_USE_JX */
31658
31659#if defined(DUK_USE_JX)
31660DUK_LOCAL void duk__dec_buffer(duk_json_dec_ctx *js_ctx) {
31661 duk_hthread *thr = js_ctx->thr;
31662 duk_context *ctx = (duk_context *) thr;
31663 const duk_uint8_t *p;
31664 duk_uint8_t *buf;
31665 duk_size_t src_len;
31666 duk_small_int_t x;
31667
31668 /* Caller has already eaten the first character ('|') which we don't need. */
31669
31670 p = js_ctx->p;
31671
31672 /* XXX: Would be nice to share the fast path loop from duk_hex_decode()
31673 * and avoid creating a temporary buffer. However, there are some
31674 * differences which prevent trivial sharing:
31675 *
31676 * - Pipe char detection
31677 * - EOF detection
31678 * - Unknown length of input and output
31679 *
31680 * The best approach here would be a bufwriter and a reasonaly sized
31681 * safe inner loop (e.g. 64 output bytes at a time).
31682 */
31683
31684 for (;;) {
31685 x = *p;
31686
31687 /* This loop intentionally does not ensure characters are valid
31688 * ([0-9a-fA-F]) because the hex decode call below will do that.
31689 */
31690 if (x == DUK_ASC_PIPE) {
31691 break;
31692 } else if (x <= 0) {
31693 /* NUL term or -1 (EOF), NUL check would suffice */
31694 goto syntax_error;
31695 }
31696 p++;
31697 }
31698
31699 /* XXX: this is not very nice; unnecessary copy is made. */
31700 src_len = (duk_size_t) (p - js_ctx->p);
31701 buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, src_len);
31702 DUK_ASSERT(buf != NULL);
31703 DUK_MEMCPY((void *) buf, (const void *) js_ctx->p, src_len);
31704 duk_hex_decode(ctx, -1);
31705
31706 js_ctx->p = p + 1; /* skip '|' */
31707
31708 /* [ ... buf ] */
31709
31710 return;
31711
31712 syntax_error:
31713 duk__dec_syntax_error(js_ctx);
31714 DUK_UNREACHABLE();
31715}
31716#endif /* DUK_USE_JX */
31717
31718/* Parse a number, other than NaN or +/- Infinity */
31719DUK_LOCAL void duk__dec_number(duk_json_dec_ctx *js_ctx) {
31720 duk_context *ctx = (duk_context *) js_ctx->thr;
31721 const duk_uint8_t *p_start;
31722 const duk_uint8_t *p;
31723 duk_uint8_t x;
31724 duk_small_uint_t s2n_flags;
31725
31726 DUK_DDD(DUK_DDDPRINT("parse_number"));
31727
31728 p_start = js_ctx->p;
31729
31730 /* First pass parse is very lenient (e.g. allows '1.2.3') and extracts a
31731 * string for strict number parsing.
31732 */
31733
31734 p = js_ctx->p;
31735 for (;;) {
31736 x = *p;
31737
31738 DUK_DDD(DUK_DDDPRINT("parse_number: p_start=%p, p=%p, p_end=%p, x=%ld",
31739 (const void *) p_start, (const void *) p,
31740 (const void *) js_ctx->p_end, (long) x));
31741
31742#if defined(DUK_USE_JSON_DECNUMBER_FASTPATH)
31743 /* This fast path is pretty marginal in practice.
31744 * XXX: candidate for removal.
31745 */
31746 DUK_ASSERT(duk__json_decnumber_lookup[0x00] == 0x00); /* end-of-input breaks */
31747 if (duk__json_decnumber_lookup[x] == 0) {
31748 break;
31749 }
31750#else /* DUK_USE_JSON_DECNUMBER_FASTPATH */
31751 if (!((x >= DUK_ASC_0 && x <= DUK_ASC_9) ||
31752 (x == DUK_ASC_PERIOD || x == DUK_ASC_LC_E ||
31753 x == DUK_ASC_UC_E || x == DUK_ASC_MINUS || x == DUK_ASC_PLUS))) {
31754 /* Plus sign must be accepted for positive exponents
31755 * (e.g. '1.5e+2'). This clause catches NULs.
31756 */
31757 break;
31758 }
31759#endif /* DUK_USE_JSON_DECNUMBER_FASTPATH */
31760 p++; /* safe, because matched (NUL causes a break) */
31761 }
31762 js_ctx->p = p;
31763
31764 DUK_ASSERT(js_ctx->p > p_start);
31765 duk_push_lstring(ctx, (const char *) p_start, (duk_size_t) (p - p_start));
31766
31767 s2n_flags = DUK_S2N_FLAG_ALLOW_EXP |
31768 DUK_S2N_FLAG_ALLOW_MINUS | /* but don't allow leading plus */
31769 DUK_S2N_FLAG_ALLOW_FRAC;
31770
31771 DUK_DDD(DUK_DDDPRINT("parse_number: string before parsing: %!T",
31772 (duk_tval *) duk_get_tval(ctx, -1)));
31773 duk_numconv_parse(ctx, 10 /*radix*/, s2n_flags);
31774 if (duk_is_nan(ctx, -1)) {
31775 duk__dec_syntax_error(js_ctx);
31776 }
31777 DUK_ASSERT(duk_is_number(ctx, -1));
31778 DUK_DDD(DUK_DDDPRINT("parse_number: final number: %!T",
31779 (duk_tval *) duk_get_tval(ctx, -1)));
31780
31781 /* [ ... num ] */
31782}
31783
31784DUK_LOCAL void duk__dec_objarr_entry(duk_json_dec_ctx *js_ctx) {
31785 duk_context *ctx = (duk_context *) js_ctx->thr;
31786 duk_require_stack(ctx, DUK_JSON_DEC_REQSTACK);
31787
31788 /* c recursion check */
31789
31790 DUK_ASSERT(js_ctx->recursion_depth >= 0);
31791 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
31792 if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
31793 DUK_ERROR_RANGE((duk_hthread *) ctx, DUK_STR_JSONDEC_RECLIMIT);
31794 }
31795 js_ctx->recursion_depth++;
31796}
31797
31798DUK_LOCAL void duk__dec_objarr_exit(duk_json_dec_ctx *js_ctx) {
31799 /* c recursion check */
31800
31801 DUK_ASSERT(js_ctx->recursion_depth > 0);
31802 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
31803 js_ctx->recursion_depth--;
31804}
31805
31806DUK_LOCAL void duk__dec_object(duk_json_dec_ctx *js_ctx) {
31807 duk_context *ctx = (duk_context *) js_ctx->thr;
31808 duk_int_t key_count; /* XXX: a "first" flag would suffice */
31809 duk_uint8_t x;
31810
31811 DUK_DDD(DUK_DDDPRINT("parse_object"));
31812
31813 duk__dec_objarr_entry(js_ctx);
31814
31815 duk_push_object(ctx);
31816
31817 /* Initial '{' has been checked and eaten by caller. */
31818
31819 key_count = 0;
31820 for (;;) {
31821 x = duk__dec_get_nonwhite(js_ctx);
31822
31823 DUK_DDD(DUK_DDDPRINT("parse_object: obj=%!T, x=%ld, key_count=%ld",
31824 (duk_tval *) duk_get_tval(ctx, -1),
31825 (long) x, (long) key_count));
31826
31827 /* handle comma and closing brace */
31828
31829 if (x == DUK_ASC_COMMA && key_count > 0) {
31830 /* accept comma, expect new value */
31831 x = duk__dec_get_nonwhite(js_ctx);
31832 } else if (x == DUK_ASC_RCURLY) {
31833 /* eat closing brace */
31834 break;
31835 } else if (key_count == 0) {
31836 /* accept anything, expect first value (EOF will be
31837 * caught by key parsing below.
31838 */
31839 ;
31840 } else {
31841 /* catches EOF (NUL) and initial comma */
31842 goto syntax_error;
31843 }
31844
31845 /* parse key and value */
31846
31847 if (x == DUK_ASC_DOUBLEQUOTE) {
31848 duk__dec_string(js_ctx);
31849#if defined(DUK_USE_JX)
31850 } else if (js_ctx->flag_ext_custom &&
31851 duk_unicode_is_identifier_start((duk_codepoint_t) x)) {
31852 duk__dec_plain_string(js_ctx);
31853#endif
31854 } else {
31855 goto syntax_error;
31856 }
31857
31858 /* [ ... obj key ] */
31859
31860 x = duk__dec_get_nonwhite(js_ctx);
31861 if (x != DUK_ASC_COLON) {
31862 goto syntax_error;
31863 }
31864
31865 duk__dec_value(js_ctx);
31866
31867 /* [ ... obj key val ] */
31868
31869 duk_xdef_prop_wec(ctx, -3);
31870
31871 /* [ ... obj ] */
31872
31873 key_count++;
31874 }
31875
31876 /* [ ... obj ] */
31877
31878 DUK_DDD(DUK_DDDPRINT("parse_object: final object is %!T",
31879 (duk_tval *) duk_get_tval(ctx, -1)));
31880
31881 duk__dec_objarr_exit(js_ctx);
31882 return;
31883
31884 syntax_error:
31885 duk__dec_syntax_error(js_ctx);
31886 DUK_UNREACHABLE();
31887}
31888
31889DUK_LOCAL void duk__dec_array(duk_json_dec_ctx *js_ctx) {
31890 duk_context *ctx = (duk_context *) js_ctx->thr;
31891 duk_uarridx_t arr_idx;
31892 duk_uint8_t x;
31893
31894 DUK_DDD(DUK_DDDPRINT("parse_array"));
31895
31896 duk__dec_objarr_entry(js_ctx);
31897
31898 duk_push_array(ctx);
31899
31900 /* Initial '[' has been checked and eaten by caller. */
31901
31902 arr_idx = 0;
31903 for (;;) {
31904 x = duk__dec_get_nonwhite(js_ctx);
31905
31906 DUK_DDD(DUK_DDDPRINT("parse_array: arr=%!T, x=%ld, arr_idx=%ld",
31907 (duk_tval *) duk_get_tval(ctx, -1),
31908 (long) x, (long) arr_idx));
31909
31910 /* handle comma and closing bracket */
31911
31912 if ((x == DUK_ASC_COMMA) && (arr_idx != 0)) {
31913 /* accept comma, expect new value */
31914 ;
31915 } else if (x == DUK_ASC_RBRACKET) {
31916 /* eat closing bracket */
31917 break;
31918 } else if (arr_idx == 0) {
31919 /* accept anything, expect first value (EOF will be
31920 * caught by duk__dec_value() below.
31921 */
31922 js_ctx->p--; /* backtrack (safe) */
31923 } else {
31924 /* catches EOF (NUL) and initial comma */
31925 goto syntax_error;
31926 }
31927
31928 /* parse value */
31929
31930 duk__dec_value(js_ctx);
31931
31932 /* [ ... arr val ] */
31933
31934 duk_xdef_prop_index_wec(ctx, -2, arr_idx);
31935 arr_idx++;
31936 }
31937
31938 /* Must set 'length' explicitly when using duk_xdef_prop_xxx() to
31939 * set the values.
31940 */
31941
31942 duk_set_length(ctx, -1, arr_idx);
31943
31944 /* [ ... arr ] */
31945
31946 DUK_DDD(DUK_DDDPRINT("parse_array: final array is %!T",
31947 (duk_tval *) duk_get_tval(ctx, -1)));
31948
31949 duk__dec_objarr_exit(js_ctx);
31950 return;
31951
31952 syntax_error:
31953 duk__dec_syntax_error(js_ctx);
31954 DUK_UNREACHABLE();
31955}
31956
31957DUK_LOCAL void duk__dec_value(duk_json_dec_ctx *js_ctx) {
31958 duk_context *ctx = (duk_context *) js_ctx->thr;
31959 duk_uint8_t x;
31960
31961 x = duk__dec_get_nonwhite(js_ctx);
31962
31963 DUK_DDD(DUK_DDDPRINT("parse_value: initial x=%ld", (long) x));
31964
31965 /* Note: duk__dec_req_stridx() backtracks one char */
31966
31967 if (x == DUK_ASC_DOUBLEQUOTE) {
31968 duk__dec_string(js_ctx);
31969 } else if ((x >= DUK_ASC_0 && x <= DUK_ASC_9) || (x == DUK_ASC_MINUS)) {
31970#if defined(DUK_USE_JX)
31971 if (js_ctx->flag_ext_custom && x == DUK_ASC_MINUS && duk__dec_peek(js_ctx) == DUK_ASC_UC_I) {
31972 duk__dec_req_stridx(js_ctx, DUK_STRIDX_MINUS_INFINITY); /* "-Infinity", '-' has been eaten */
31973 duk_push_number(ctx, -DUK_DOUBLE_INFINITY);
31974 } else {
31975#else
31976 { /* unconditional block */
31977#endif
31978 /* We already ate 'x', so backup one byte. */
31979 js_ctx->p--; /* safe */
31980 duk__dec_number(js_ctx);
31981 }
31982 } else if (x == DUK_ASC_LC_T) {
31983 duk__dec_req_stridx(js_ctx, DUK_STRIDX_TRUE);
31984 duk_push_true(ctx);
31985 } else if (x == DUK_ASC_LC_F) {
31986 duk__dec_req_stridx(js_ctx, DUK_STRIDX_FALSE);
31987 duk_push_false(ctx);
31988 } else if (x == DUK_ASC_LC_N) {
31989 duk__dec_req_stridx(js_ctx, DUK_STRIDX_LC_NULL);
31990 duk_push_null(ctx);
31991#if defined(DUK_USE_JX)
31992 } else if (js_ctx->flag_ext_custom && x == DUK_ASC_LC_U) {
31993 duk__dec_req_stridx(js_ctx, DUK_STRIDX_LC_UNDEFINED);
31994 duk_push_undefined(ctx);
31995 } else if (js_ctx->flag_ext_custom && x == DUK_ASC_UC_N) {
31996 duk__dec_req_stridx(js_ctx, DUK_STRIDX_NAN);
31997 duk_push_nan(ctx);
31998 } else if (js_ctx->flag_ext_custom && x == DUK_ASC_UC_I) {
31999 duk__dec_req_stridx(js_ctx, DUK_STRIDX_INFINITY);
32000 duk_push_number(ctx, DUK_DOUBLE_INFINITY);
32001 } else if (js_ctx->flag_ext_custom && x == DUK_ASC_LPAREN) {
32002 duk__dec_pointer(js_ctx);
32003 } else if (js_ctx->flag_ext_custom && x == DUK_ASC_PIPE) {
32004 duk__dec_buffer(js_ctx);
32005#endif
32006 } else if (x == DUK_ASC_LCURLY) {
32007 duk__dec_object(js_ctx);
32008 } else if (x == DUK_ASC_LBRACKET) {
32009 duk__dec_array(js_ctx);
32010 } else {
32011 /* catches EOF (NUL) */
32012 goto syntax_error;
32013 }
32014
32015 duk__dec_eat_white(js_ctx);
32016
32017 /* [ ... val ] */
32018 return;
32019
32020 syntax_error:
32021 duk__dec_syntax_error(js_ctx);
32022 DUK_UNREACHABLE();
32023}
32024
32025/* Recursive value reviver, implements the Walk() algorithm. No C recursion
32026 * check is done here because the initial parsing step will already ensure
32027 * there is a reasonable limit on C recursion depth and hence object depth.
32028 */
32029DUK_LOCAL void duk__dec_reviver_walk(duk_json_dec_ctx *js_ctx) {
32030 duk_context *ctx = (duk_context *) js_ctx->thr;
32031 duk_hobject *h;
32032 duk_uarridx_t i, arr_len;
32033
32034 DUK_DDD(DUK_DDDPRINT("walk: top=%ld, holder=%!T, name=%!T",
32035 (long) duk_get_top(ctx),
32036 (duk_tval *) duk_get_tval(ctx, -2),
32037 (duk_tval *) duk_get_tval(ctx, -1)));
32038
32039 duk_dup_top(ctx);
32040 duk_get_prop(ctx, -3); /* -> [ ... holder name val ] */
32041
32042 h = duk_get_hobject(ctx, -1);
32043 if (h != NULL) {
32044 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) {
32045 arr_len = (duk_uarridx_t) duk_get_length(ctx, -1);
32046 for (i = 0; i < arr_len; i++) {
32047 /* [ ... holder name val ] */
32048
32049 DUK_DDD(DUK_DDDPRINT("walk: array, top=%ld, i=%ld, arr_len=%ld, holder=%!T, name=%!T, val=%!T",
32050 (long) duk_get_top(ctx), (long) i, (long) arr_len,
32051 (duk_tval *) duk_get_tval(ctx, -3), (duk_tval *) duk_get_tval(ctx, -2),
32052 (duk_tval *) duk_get_tval(ctx, -1)));
32053
32054 duk_dup_top(ctx);
32055 (void) duk_push_uint_to_hstring(ctx, (duk_uint_t) i); /* -> [ ... holder name val val ToString(i) ] */
32056 duk__dec_reviver_walk(js_ctx); /* -> [ ... holder name val new_elem ] */
32057
32058 if (duk_is_undefined(ctx, -1)) {
32059 duk_pop(ctx);
32060 duk_del_prop_index(ctx, -1, i);
32061 } else {
32062 /* XXX: duk_xdef_prop_index_wec() would be more appropriate
32063 * here but it currently makes some assumptions that might
32064 * not hold (e.g. that previous property is not an accessor).
32065 */
32066 duk_put_prop_index(ctx, -2, i);
32067 }
32068 }
32069 } else {
32070 /* [ ... holder name val ] */
32071 duk_enum(ctx, -1, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/);
32072 while (duk_next(ctx, -1 /*enum_index*/, 0 /*get_value*/)) {
32073 DUK_DDD(DUK_DDDPRINT("walk: object, top=%ld, holder=%!T, name=%!T, val=%!T, enum=%!iT, obj_key=%!T",
32074 (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, -5),
32075 (duk_tval *) duk_get_tval(ctx, -4), (duk_tval *) duk_get_tval(ctx, -3),
32076 (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1)));
32077
32078 /* [ ... holder name val enum obj_key ] */
32079 duk_dup_m3(ctx);
32080 duk_dup_m2(ctx);
32081
32082 /* [ ... holder name val enum obj_key val obj_key ] */
32083 duk__dec_reviver_walk(js_ctx);
32084
32085 /* [ ... holder name val enum obj_key new_elem ] */
32086 if (duk_is_undefined(ctx, -1)) {
32087 duk_pop(ctx);
32088 duk_del_prop(ctx, -3);
32089 } else {
32090 /* XXX: duk_xdef_prop_index_wec() would be more appropriate
32091 * here but it currently makes some assumptions that might
32092 * not hold (e.g. that previous property is not an accessor).
32093 *
32094 * Using duk_put_prop() works incorrectly with '__proto__'
32095 * if the own property with that name has been deleted. This
32096 * does not happen normally, but a clever reviver can trigger
32097 * that, see complex reviver case in: test-bug-json-parse-__proto__.js.
32098 */
32099 duk_put_prop(ctx, -4);
32100 }
32101 }
32102 duk_pop(ctx); /* pop enum */
32103 }
32104 }
32105
32106 /* [ ... holder name val ] */
32107
32108 duk_dup(ctx, js_ctx->idx_reviver);
32109 duk_insert(ctx, -4); /* -> [ ... reviver holder name val ] */
32110 duk_call_method(ctx, 2); /* -> [ ... res ] */
32111
32112 DUK_DDD(DUK_DDDPRINT("walk: top=%ld, result=%!T",
32113 (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, -1)));
32114}
32115
32116/*
32117 * Stringify implementation.
32118 */
32119
32120#define DUK__EMIT_1(js_ctx,ch) duk__emit_1((js_ctx), (duk_uint_fast8_t) (ch))
32121#define DUK__EMIT_2(js_ctx,ch1,ch2) duk__emit_2((js_ctx), (duk_uint_fast8_t) (ch1), (duk_uint_fast8_t) (ch2))
32122#define DUK__EMIT_HSTR(js_ctx,h) duk__emit_hstring((js_ctx), (h))
32123#if defined(DUK_USE_FASTINT) || defined(DUK_USE_JX) || defined(DUK_USE_JC)
32124#define DUK__EMIT_CSTR(js_ctx,p) duk__emit_cstring((js_ctx), (p))
32125#endif
32126#define DUK__EMIT_STRIDX(js_ctx,i) duk__emit_stridx((js_ctx), (i))
32127#define DUK__UNEMIT_1(js_ctx) duk__unemit_1((js_ctx))
32128
32129DUK_LOCAL void duk__emit_1(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch) {
32130 DUK_BW_WRITE_ENSURE_U8(js_ctx->thr, &js_ctx->bw, ch);
32131}
32132
32133DUK_LOCAL void duk__emit_2(duk_json_enc_ctx *js_ctx, duk_uint_fast8_t ch1, duk_uint_fast8_t ch2) {
32134 DUK_BW_WRITE_ENSURE_U8_2(js_ctx->thr, &js_ctx->bw, ch1, ch2);
32135}
32136
32137DUK_LOCAL void duk__emit_hstring(duk_json_enc_ctx *js_ctx, duk_hstring *h) {
32138 DUK_BW_WRITE_ENSURE_HSTRING(js_ctx->thr, &js_ctx->bw, h);
32139}
32140
32141#if defined(DUK_USE_FASTINT) || defined(DUK_USE_JX) || defined(DUK_USE_JC)
32142DUK_LOCAL void duk__emit_cstring(duk_json_enc_ctx *js_ctx, const char *str) {
32143 DUK_BW_WRITE_ENSURE_CSTRING(js_ctx->thr, &js_ctx->bw, str);
32144}
32145#endif
32146
32147DUK_LOCAL void duk__emit_stridx(duk_json_enc_ctx *js_ctx, duk_small_uint_t stridx) {
32148 duk_hstring *h;
32149
32150 DUK_ASSERT_STRIDX_VALID(stridx);
32151 h = DUK_HTHREAD_GET_STRING(js_ctx->thr, stridx);
32152 DUK_ASSERT(h != NULL);
32153
32154 DUK_BW_WRITE_ENSURE_HSTRING(js_ctx->thr, &js_ctx->bw, h);
32155}
32156
32157DUK_LOCAL void duk__unemit_1(duk_json_enc_ctx *js_ctx) {
32158 DUK_ASSERT(DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw) >= 1);
32159 DUK_BW_ADD_PTR(js_ctx->thr, &js_ctx->bw, -1);
32160}
32161
32162#define DUK__MKESC(nybbles,esc1,esc2) \
32163 (((duk_uint_fast32_t) (nybbles)) << 16) | \
32164 (((duk_uint_fast32_t) (esc1)) << 8) | \
32165 ((duk_uint_fast32_t) (esc2))
32166
32167DUK_LOCAL duk_uint8_t *duk__emit_esc_auto_fast(duk_json_enc_ctx *js_ctx, duk_uint_fast32_t cp, duk_uint8_t *q) {
32168 duk_uint_fast32_t tmp;
32169 duk_small_uint_t dig;
32170
32171 DUK_UNREF(js_ctx);
32172
32173 /* Caller ensures space for at least DUK__JSON_MAX_ESC_LEN. */
32174
32175 /* Select appropriate escape format automatically, and set 'tmp' to a
32176 * value encoding both the escape format character and the nybble count:
32177 *
32178 * (nybble_count << 16) | (escape_char1) | (escape_char2)
32179 */
32180
32181#if defined(DUK_USE_JX)
32182 if (DUK_LIKELY(cp < 0x100UL)) {
32183 if (DUK_UNLIKELY(js_ctx->flag_ext_custom)) {
32184 tmp = DUK__MKESC(2, DUK_ASC_BACKSLASH, DUK_ASC_LC_X);
32185 } else {
32186 tmp = DUK__MKESC(4, DUK_ASC_BACKSLASH, DUK_ASC_LC_U);
32187 }
32188 } else
32189#endif
32190 if (DUK_LIKELY(cp < 0x10000UL)) {
32191 tmp = DUK__MKESC(4, DUK_ASC_BACKSLASH, DUK_ASC_LC_U);
32192 } else {
32193#if defined(DUK_USE_JX)
32194 if (DUK_LIKELY(js_ctx->flag_ext_custom)) {
32195 tmp = DUK__MKESC(8, DUK_ASC_BACKSLASH, DUK_ASC_UC_U);
32196 } else
32197#endif
32198 {
32199 /* In compatible mode and standard JSON mode, output
32200 * something useful for non-BMP characters. This won't
32201 * roundtrip but will still be more or less readable and
32202 * more useful than an error.
32203 */
32204 tmp = DUK__MKESC(8, DUK_ASC_UC_U, DUK_ASC_PLUS);
32205 }
32206 }
32207
32208 *q++ = (duk_uint8_t) ((tmp >> 8) & 0xff);
32209 *q++ = (duk_uint8_t) (tmp & 0xff);
32210
32211 tmp = tmp >> 16;
32212 while (tmp > 0) {
32213 tmp--;
32214 dig = (duk_small_uint_t) ((cp >> (4 * tmp)) & 0x0f);
32215 *q++ = duk_lc_digits[dig];
32216 }
32217
32218 return q;
32219}
32220
32221DUK_LOCAL void duk__enc_key_autoquote(duk_json_enc_ctx *js_ctx, duk_hstring *k) {
32222 const duk_int8_t *p, *p_start, *p_end; /* Note: intentionally signed. */
32223 duk_size_t k_len;
32224 duk_codepoint_t cp;
32225
32226 DUK_ASSERT(k != NULL);
32227
32228 /* Accept ASCII strings which conform to identifier requirements
32229 * as being emitted without key quotes. Since we only accept ASCII
32230 * there's no need for actual decoding: 'p' is intentionally signed
32231 * so that bytes >= 0x80 extend to negative values and are rejected
32232 * as invalid identifier codepoints.
32233 */
32234
32235 if (js_ctx->flag_avoid_key_quotes) {
32236 k_len = DUK_HSTRING_GET_BYTELEN(k);
32237 p_start = (const duk_int8_t *) DUK_HSTRING_GET_DATA(k);
32238 p_end = p_start + k_len;
32239 p = p_start;
32240
32241 if (p == p_end) {
32242 /* Zero length string is not accepted without quotes */
32243 goto quote_normally;
32244 }
32245 cp = (duk_codepoint_t) (*p++);
32246 if (DUK_UNLIKELY(!duk_unicode_is_identifier_start(cp))) {
32247 goto quote_normally;
32248 }
32249 while (p < p_end) {
32250 cp = (duk_codepoint_t) (*p++);
32251 if (DUK_UNLIKELY(!duk_unicode_is_identifier_part(cp))) {
32252 goto quote_normally;
32253 }
32254 }
32255
32256 /* This seems faster than emitting bytes one at a time and
32257 * then potentially rewinding.
32258 */
32259 DUK__EMIT_HSTR(js_ctx, k);
32260 return;
32261 }
32262
32263 quote_normally:
32264 duk__enc_quote_string(js_ctx, k);
32265}
32266
32267/* The Quote(value) operation: quote a string.
32268 *
32269 * Stack policy: [ ] -> [ ].
32270 */
32271
32272DUK_LOCAL void duk__enc_quote_string(duk_json_enc_ctx *js_ctx, duk_hstring *h_str) {
32273 duk_hthread *thr = js_ctx->thr;
32274 const duk_uint8_t *p, *p_start, *p_end, *p_now, *p_tmp;
32275 duk_uint8_t *q;
32276 duk_ucodepoint_t cp; /* typed for duk_unicode_decode_xutf8() */
32277
32278 DUK_DDD(DUK_DDDPRINT("duk__enc_quote_string: h_str=%!O", (duk_heaphdr *) h_str));
32279
32280 DUK_ASSERT(h_str != NULL);
32281 p_start = DUK_HSTRING_GET_DATA(h_str);
32282 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_str);
32283 p = p_start;
32284
32285 DUK__EMIT_1(js_ctx, DUK_ASC_DOUBLEQUOTE);
32286
32287 /* Encode string in small chunks, estimating the maximum expansion so that
32288 * there's no need to ensure space while processing the chunk.
32289 */
32290
32291 while (p < p_end) {
32292 duk_size_t left, now, space;
32293
32294 left = (duk_size_t) (p_end - p);
32295 now = (left > DUK__JSON_ENCSTR_CHUNKSIZE ?
32296 DUK__JSON_ENCSTR_CHUNKSIZE : left);
32297
32298 /* Maximum expansion per input byte is 6:
32299 * - invalid UTF-8 byte causes "\uXXXX" to be emitted (6/1 = 6).
32300 * - 2-byte UTF-8 encodes as "\uXXXX" (6/2 = 3).
32301 * - 4-byte UTF-8 encodes as "\Uxxxxxxxx" (10/4 = 2.5).
32302 */
32303 space = now * 6;
32304 q = DUK_BW_ENSURE_GETPTR(thr, &js_ctx->bw, space);
32305
32306 p_now = p + now;
32307
32308 while (p < p_now) {
32309#if defined(DUK_USE_JSON_QUOTESTRING_FASTPATH)
32310 duk_uint8_t b;
32311
32312 b = duk__json_quotestr_lookup[*p++];
32313 if (DUK_LIKELY(b < 0x80)) {
32314 /* Most input bytes go through here. */
32315 *q++ = b;
32316 } else if (b >= 0xa0) {
32317 *q++ = DUK_ASC_BACKSLASH;
32318 *q++ = (duk_uint8_t) (b - 0x80);
32319 } else if (b == 0x80) {
32320 cp = (duk_ucodepoint_t) (*(p - 1));
32321 q = duk__emit_esc_auto_fast(js_ctx, cp, q);
32322 } else if (b == 0x7f && js_ctx->flag_ascii_only) {
32323 /* 0x7F is special */
32324 DUK_ASSERT(b == 0x81);
32325 cp = (duk_ucodepoint_t) 0x7f;
32326 q = duk__emit_esc_auto_fast(js_ctx, cp, q);
32327 } else {
32328 DUK_ASSERT(b == 0x81);
32329 p--;
32330
32331 /* slow path is shared */
32332#else /* DUK_USE_JSON_QUOTESTRING_FASTPATH */
32333 cp = *p;
32334
32335 if (DUK_LIKELY(cp <= 0x7f)) {
32336 /* ascii fast path: avoid decoding utf-8 */
32337 p++;
32338 if (cp == 0x22 || cp == 0x5c) {
32339 /* double quote or backslash */
32340 *q++ = DUK_ASC_BACKSLASH;
32341 *q++ = (duk_uint8_t) cp;
32342 } else if (cp < 0x20) {
32343 duk_uint_fast8_t esc_char;
32344
32345 /* This approach is a bit shorter than a straight
32346 * if-else-ladder and also a bit faster.
32347 */
32348 if (cp < (sizeof(duk__json_quotestr_esc) / sizeof(duk_uint8_t)) &&
32349 (esc_char = duk__json_quotestr_esc[cp]) != 0) {
32350 *q++ = DUK_ASC_BACKSLASH;
32351 *q++ = (duk_uint8_t) esc_char;
32352 } else {
32353 q = duk__emit_esc_auto_fast(js_ctx, cp, q);
32354 }
32355 } else if (cp == 0x7f && js_ctx->flag_ascii_only) {
32356 q = duk__emit_esc_auto_fast(js_ctx, cp, q);
32357 } else {
32358 /* any other printable -> as is */
32359 *q++ = (duk_uint8_t) cp;
32360 }
32361 } else {
32362 /* slow path is shared */
32363#endif /* DUK_USE_JSON_QUOTESTRING_FASTPATH */
32364
32365 /* slow path decode */
32366
32367 /* If XUTF-8 decoding fails, treat the offending byte as a codepoint directly
32368 * and go forward one byte. This is of course very lossy, but allows some kind
32369 * of output to be produced even for internal strings which don't conform to
32370 * XUTF-8. All standard Ecmascript strings are always CESU-8, so this behavior
32371 * does not violate the Ecmascript specification. The behavior is applied to
32372 * all modes, including Ecmascript standard JSON. Because the current XUTF-8
32373 * decoding is not very strict, this behavior only really affects initial bytes
32374 * and truncated codepoints.
32375 *
32376 * Another alternative would be to scan forwards to start of next codepoint
32377 * (or end of input) and emit just one replacement codepoint.
32378 */
32379
32380 p_tmp = p;
32381 if (!duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp)) {
32382 /* Decode failed. */
32383 cp = *p_tmp;
32384 p = p_tmp + 1;
32385 }
32386
32387#if defined(DUK_USE_NONSTD_JSON_ESC_U2028_U2029)
32388 if (js_ctx->flag_ascii_only || cp == 0x2028 || cp == 0x2029) {
32389#else
32390 if (js_ctx->flag_ascii_only) {
32391#endif
32392 q = duk__emit_esc_auto_fast(js_ctx, cp, q);
32393 } else {
32394 /* as is */
32395 DUK_RAW_WRITE_XUTF8(q, cp);
32396 }
32397 }
32398 }
32399
32400 DUK_BW_SET_PTR(thr, &js_ctx->bw, q);
32401 }
32402
32403 DUK__EMIT_1(js_ctx, DUK_ASC_DOUBLEQUOTE);
32404}
32405
32406/* Encode a double (checked by caller) from stack top. Stack top may be
32407 * replaced by serialized string but is not popped (caller does that).
32408 */
32409DUK_LOCAL void duk__enc_double(duk_json_enc_ctx *js_ctx) {
32410 duk_hthread *thr;
32411 duk_context *ctx;
32412 duk_tval *tv;
32413 duk_double_t d;
32414 duk_small_int_t c;
32415 duk_small_int_t s;
32416 duk_small_uint_t stridx;
32417 duk_small_uint_t n2s_flags;
32418 duk_hstring *h_str;
32419
32420 DUK_ASSERT(js_ctx != NULL);
32421 thr = js_ctx->thr;
32422 DUK_ASSERT(thr != NULL);
32423 ctx = (duk_context *) thr;
32424
32425 /* Caller must ensure 'tv' is indeed a double and not a fastint! */
32426 tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
32427 DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
32428 d = DUK_TVAL_GET_DOUBLE(tv);
32429
32430 c = (duk_small_int_t) DUK_FPCLASSIFY(d);
32431 s = (duk_small_int_t) DUK_SIGNBIT(d);
32432 DUK_UNREF(s);
32433
32434 if (DUK_LIKELY(!(c == DUK_FP_INFINITE || c == DUK_FP_NAN))) {
32435 DUK_ASSERT(DUK_ISFINITE(d));
32436
32437#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
32438 /* Negative zero needs special handling in JX/JC because
32439 * it would otherwise serialize to '0', not '-0'.
32440 */
32441 if (DUK_UNLIKELY(c == DUK_FP_ZERO && s != 0 &&
32442 (js_ctx->flag_ext_custom_or_compatible))) {
32443 duk_push_hstring_stridx(ctx, DUK_STRIDX_MINUS_ZERO); /* '-0' */
32444 } else
32445#endif /* DUK_USE_JX || DUK_USE_JC */
32446 {
32447 n2s_flags = 0;
32448 /* [ ... number ] -> [ ... string ] */
32449 duk_numconv_stringify(ctx, 10 /*radix*/, 0 /*digits*/, n2s_flags);
32450 }
32451 h_str = duk_known_hstring(ctx, -1);
32452 DUK__EMIT_HSTR(js_ctx, h_str);
32453 return;
32454 }
32455
32456#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
32457 if (!(js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM |
32458 DUK_JSON_FLAG_EXT_COMPATIBLE))) {
32459 stridx = DUK_STRIDX_LC_NULL;
32460 } else if (c == DUK_FP_NAN) {
32461 stridx = js_ctx->stridx_custom_nan;
32462 } else if (s == 0) {
32463 stridx = js_ctx->stridx_custom_posinf;
32464 } else {
32465 stridx = js_ctx->stridx_custom_neginf;
32466 }
32467#else
32468 stridx = DUK_STRIDX_LC_NULL;
32469#endif
32470 DUK__EMIT_STRIDX(js_ctx, stridx);
32471}
32472
32473#if defined(DUK_USE_FASTINT)
32474/* Encode a fastint from duk_tval ptr, no value stack effects. */
32475DUK_LOCAL void duk__enc_fastint_tval(duk_json_enc_ctx *js_ctx, duk_tval *tv) {
32476 duk_int64_t v;
32477
32478 /* Fastint range is signed 48-bit so longest value is -2^47 = -140737488355328
32479 * (16 chars long), longest signed 64-bit value is -2^63 = -9223372036854775808
32480 * (20 chars long). Alloc space for 64-bit range to be safe.
32481 */
32482 duk_uint8_t buf[20 + 1];
32483
32484 /* Caller must ensure 'tv' is indeed a fastint! */
32485 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv));
32486 v = DUK_TVAL_GET_FASTINT(tv);
32487
32488 /* XXX: There are no format strings in duk_config.h yet, could add
32489 * one for formatting duk_int64_t. For now, assumes "%lld" and that
32490 * "long long" type exists. Could also rely on C99 directly but that
32491 * won't work for older MSVC.
32492 */
32493 DUK_SPRINTF((char *) buf, "%lld", (long long) v);
32494 DUK__EMIT_CSTR(js_ctx, (const char *) buf);
32495}
32496#endif
32497
32498#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
32499#if defined(DUK_USE_HEX_FASTPATH)
32500DUK_LOCAL duk_uint8_t *duk__enc_buffer_data_hex(const duk_uint8_t *src, duk_size_t src_len, duk_uint8_t *dst) {
32501 duk_uint8_t *q;
32502 duk_uint16_t *q16;
32503 duk_small_uint_t x;
32504 duk_size_t i, len_safe;
32505#if !defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE)
32506 duk_bool_t shift_dst;
32507#endif
32508
32509 /* Unlike in duk_hex_encode() 'dst' is not necessarily aligned by 2.
32510 * For platforms where unaligned accesses are not allowed, shift 'dst'
32511 * ahead by 1 byte to get alignment and then DUK_MEMMOVE() the result
32512 * in place. The faster encoding loop makes up the difference.
32513 * There's always space for one extra byte because a terminator always
32514 * follows the hex data and that's been accounted for by the caller.
32515 */
32516
32517#if defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE)
32518 q16 = (duk_uint16_t *) (void *) dst;
32519#else
32520 shift_dst = (duk_bool_t) (((duk_size_t) dst) & 0x01U);
32521 if (shift_dst) {
32522 DUK_DD(DUK_DDPRINT("unaligned accesses not possible, dst not aligned -> step to dst + 1"));
32523 q16 = (duk_uint16_t *) (void *) (dst + 1);
32524 } else {
32525 DUK_DD(DUK_DDPRINT("unaligned accesses not possible, dst is aligned"));
32526 q16 = (duk_uint16_t *) (void *) dst;
32527 }
32528 DUK_ASSERT((((duk_size_t) q16) & 0x01U) == 0);
32529#endif
32530
32531 len_safe = src_len & ~0x03U;
32532 for (i = 0; i < len_safe; i += 4) {
32533 q16[0] = duk_hex_enctab[src[i]];
32534 q16[1] = duk_hex_enctab[src[i + 1]];
32535 q16[2] = duk_hex_enctab[src[i + 2]];
32536 q16[3] = duk_hex_enctab[src[i + 3]];
32537 q16 += 4;
32538 }
32539 q = (duk_uint8_t *) q16;
32540
32541#if !defined(DUK_USE_UNALIGNED_ACCESSES_POSSIBLE)
32542 if (shift_dst) {
32543 q--;
32544 DUK_MEMMOVE((void *) dst, (const void *) (dst + 1), 2 * len_safe);
32545 DUK_ASSERT(dst + 2 * len_safe == q);
32546 }
32547#endif
32548
32549 for (; i < src_len; i++) {
32550 x = src[i];
32551 *q++ = duk_lc_digits[x >> 4];
32552 *q++ = duk_lc_digits[x & 0x0f];
32553 }
32554
32555 return q;
32556}
32557#else /* DUK_USE_HEX_FASTPATH */
32558DUK_LOCAL duk_uint8_t *duk__enc_buffer_data_hex(const duk_uint8_t *src, duk_size_t src_len, duk_uint8_t *dst) {
32559 const duk_uint8_t *p;
32560 const duk_uint8_t *p_end;
32561 duk_uint8_t *q;
32562 duk_small_uint_t x;
32563
32564 p = src;
32565 p_end = src + src_len;
32566 q = dst;
32567 while (p != p_end) {
32568 x = *p++;
32569 *q++ = duk_lc_digits[x >> 4];
32570 *q++ = duk_lc_digits[x & 0x0f];
32571 }
32572
32573 return q;
32574}
32575#endif /* DUK_USE_HEX_FASTPATH */
32576
32577DUK_LOCAL void duk__enc_buffer_data(duk_json_enc_ctx *js_ctx, duk_uint8_t *buf_data, duk_size_t buf_len) {
32578 duk_hthread *thr;
32579 duk_uint8_t *q;
32580 duk_size_t space;
32581
32582 thr = js_ctx->thr;
32583
32584 DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); /* caller checks */
32585 DUK_ASSERT(js_ctx->flag_ext_custom_or_compatible);
32586
32587 /* Buffer values are encoded in (lowercase) hex to make the
32588 * binary data readable. Base64 or similar would be more
32589 * compact but less readable, and the point of JX/JC
32590 * variants is to be as useful to a programmer as possible.
32591 */
32592
32593 /* The #if defined() clutter here needs to handle the three
32594 * cases: (1) JX+JC, (2) JX only, (3) JC only.
32595 */
32596
32597 /* Note: space must cater for both JX and JC. */
32598 space = 9 + buf_len * 2 + 2;
32599 DUK_ASSERT(DUK_HBUFFER_MAX_BYTELEN <= 0x7ffffffeUL);
32600 DUK_ASSERT((space - 2) / 2 >= buf_len); /* overflow not possible, buffer limits */
32601 q = DUK_BW_ENSURE_GETPTR(thr, &js_ctx->bw, space);
32602
32603#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
32604 if (js_ctx->flag_ext_custom)
32605#endif
32606#if defined(DUK_USE_JX)
32607 {
32608 *q++ = DUK_ASC_PIPE;
32609 q = duk__enc_buffer_data_hex(buf_data, buf_len, q);
32610 *q++ = DUK_ASC_PIPE;
32611
32612 }
32613#endif
32614#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
32615 else
32616#endif
32617#if defined(DUK_USE_JC)
32618 {
32619 DUK_ASSERT(js_ctx->flag_ext_compatible);
32620 DUK_MEMCPY((void *) q, (const void *) "{\"_buf\":\"", 9); /* len: 9 */
32621 q += 9;
32622 q = duk__enc_buffer_data_hex(buf_data, buf_len, q);
32623 *q++ = DUK_ASC_DOUBLEQUOTE;
32624 *q++ = DUK_ASC_RCURLY;
32625 }
32626#endif
32627
32628 DUK_BW_SET_PTR(thr, &js_ctx->bw, q);
32629}
32630
32631DUK_LOCAL void duk__enc_buffer(duk_json_enc_ctx *js_ctx, duk_hbuffer *h) {
32632 duk__enc_buffer_data(js_ctx,
32633 (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(js_ctx->thr->heap, h),
32634 (duk_size_t) DUK_HBUFFER_GET_SIZE(h));
32635}
32636#endif /* DUK_USE_JX || DUK_USE_JC */
32637
32638#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
32639DUK_LOCAL void duk__enc_pointer(duk_json_enc_ctx *js_ctx, void *ptr) {
32640 char buf[64]; /* XXX: how to figure correct size? */
32641 const char *fmt;
32642
32643 DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible); /* caller checks */
32644 DUK_ASSERT(js_ctx->flag_ext_custom_or_compatible);
32645
32646 DUK_MEMZERO(buf, sizeof(buf));
32647
32648 /* The #if defined() clutter here needs to handle the three
32649 * cases: (1) JX+JC, (2) JX only, (3) JC only.
32650 */
32651#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
32652 if (js_ctx->flag_ext_custom)
32653#endif
32654#if defined(DUK_USE_JX)
32655 {
32656 fmt = ptr ? "(%p)" : "(null)";
32657 }
32658#endif
32659#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
32660 else
32661#endif
32662#if defined(DUK_USE_JC)
32663 {
32664 DUK_ASSERT(js_ctx->flag_ext_compatible);
32665 fmt = ptr ? "{\"_ptr\":\"%p\"}" : "{\"_ptr\":\"null\"}";
32666 }
32667#endif
32668
32669 /* When ptr == NULL, the format argument is unused. */
32670 DUK_SNPRINTF(buf, sizeof(buf) - 1, fmt, ptr); /* must not truncate */
32671 DUK__EMIT_CSTR(js_ctx, buf);
32672}
32673#endif /* DUK_USE_JX || DUK_USE_JC */
32674
32675#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
32676#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
32677DUK_LOCAL void duk__enc_bufobj(duk_json_enc_ctx *js_ctx, duk_hbufobj *h_bufobj) {
32678 DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
32679
32680 if (h_bufobj->buf == NULL || !DUK_HBUFOBJ_VALID_SLICE(h_bufobj)) {
32681 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
32682 } else {
32683 /* Handle both full and partial slice (as long as covered). */
32684 duk__enc_buffer_data(js_ctx,
32685 (duk_uint8_t *) DUK_HBUFOBJ_GET_SLICE_BASE(js_ctx->thr->heap, h_bufobj),
32686 (duk_size_t) h_bufobj->length);
32687 }
32688}
32689#endif /* DUK_USE_JX || DUK_USE_JC */
32690#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
32691
32692/* Indent helper. Calling code relies on js_ctx->recursion_depth also being
32693 * directly related to indent depth.
32694 */
32695#if defined(DUK_USE_PREFER_SIZE)
32696DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth) {
32697 DUK_ASSERT(js_ctx->h_gap != NULL);
32698 DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) > 0); /* caller guarantees */
32699
32700 DUK__EMIT_1(js_ctx, 0x0a);
32701 while (depth-- > 0) {
32702 DUK__EMIT_HSTR(js_ctx, js_ctx->h_gap);
32703 }
32704}
32705#else /* DUK_USE_PREFER_SIZE */
32706DUK_LOCAL void duk__enc_newline_indent(duk_json_enc_ctx *js_ctx, duk_int_t depth) {
32707 const duk_uint8_t *gap_data;
32708 duk_size_t gap_len;
32709 duk_size_t avail_bytes; /* bytes of indent available for copying */
32710 duk_size_t need_bytes; /* bytes of indent still needed */
32711 duk_uint8_t *p_start;
32712 duk_uint8_t *p;
32713
32714 DUK_ASSERT(js_ctx->h_gap != NULL);
32715 DUK_ASSERT(DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap) > 0); /* caller guarantees */
32716
32717 DUK__EMIT_1(js_ctx, 0x0a);
32718 if (DUK_UNLIKELY(depth == 0)) {
32719 return;
32720 }
32721
32722 /* To handle deeper indents efficiently, make use of copies we've
32723 * already emitted. In effect we can emit a sequence of 1, 2, 4,
32724 * 8, etc copies, and then finish the last run. Byte counters
32725 * avoid multiply with gap_len on every loop.
32726 */
32727
32728 gap_data = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(js_ctx->h_gap);
32729 gap_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(js_ctx->h_gap);
32730 DUK_ASSERT(gap_len > 0);
32731
32732 need_bytes = gap_len * depth;
32733 p = DUK_BW_ENSURE_GETPTR(js_ctx->thr, &js_ctx->bw, need_bytes);
32734 p_start = p;
32735
32736 DUK_MEMCPY((void *) p, (const void *) gap_data, (size_t) gap_len);
32737 p += gap_len;
32738 avail_bytes = gap_len;
32739 DUK_ASSERT(need_bytes >= gap_len);
32740 need_bytes -= gap_len;
32741
32742 while (need_bytes >= avail_bytes) {
32743 DUK_MEMCPY((void *) p, (const void *) p_start, (size_t) avail_bytes);
32744 p += avail_bytes;
32745 need_bytes -= avail_bytes;
32746 avail_bytes <<= 1;
32747 }
32748
32749 DUK_ASSERT(need_bytes < avail_bytes); /* need_bytes may be zero */
32750 DUK_MEMCPY((void *) p, (const void *) p_start, (size_t) need_bytes);
32751 p += need_bytes;
32752 /*avail_bytes += need_bytes*/
32753
32754 DUK_BW_SET_PTR(js_ctx->thr, &js_ctx->bw, p);
32755}
32756#endif /* DUK_USE_PREFER_SIZE */
32757
32758/* Shared entry handling for object/array serialization. */
32759DUK_LOCAL void duk__enc_objarr_entry(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) {
32760 duk_context *ctx = (duk_context *) js_ctx->thr;
32761 duk_hobject *h_target;
32762 duk_uint_fast32_t i, n;
32763
32764 *entry_top = duk_get_top(ctx);
32765
32766 duk_require_stack(ctx, DUK_JSON_ENC_REQSTACK);
32767
32768 /* Loop check using a hybrid approach: a fixed-size visited[] array
32769 * with overflow in a loop check object.
32770 */
32771
32772 h_target = duk_known_hobject(ctx, -1); /* object or array */
32773
32774 n = js_ctx->recursion_depth;
32775 if (DUK_UNLIKELY(n > DUK_JSON_ENC_LOOPARRAY)) {
32776 n = DUK_JSON_ENC_LOOPARRAY;
32777 }
32778 for (i = 0; i < n; i++) {
32779 if (DUK_UNLIKELY(js_ctx->visiting[i] == h_target)) {
32780 DUK_DD(DUK_DDPRINT("slow path loop detect"));
32781 DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_CYCLIC_INPUT);
32782 }
32783 }
32784 if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) {
32785 js_ctx->visiting[js_ctx->recursion_depth] = h_target;
32786 } else {
32787 duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) h_target);
32788 duk_dup_top(ctx); /* -> [ ... voidp voidp ] */
32789 if (duk_has_prop(ctx, js_ctx->idx_loop)) {
32790 DUK_ERROR_TYPE((duk_hthread *) ctx, DUK_STR_CYCLIC_INPUT);
32791 }
32792 duk_push_true(ctx); /* -> [ ... voidp true ] */
32793 duk_put_prop(ctx, js_ctx->idx_loop); /* -> [ ... ] */
32794 }
32795
32796 /* C recursion check. */
32797
32798 DUK_ASSERT(js_ctx->recursion_depth >= 0);
32799 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
32800 if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
32801 DUK_ERROR_RANGE((duk_hthread *) ctx, DUK_STR_JSONENC_RECLIMIT);
32802 }
32803 js_ctx->recursion_depth++;
32804
32805 DUK_DDD(DUK_DDDPRINT("shared entry finished: top=%ld, loop=%!T",
32806 (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop)));
32807}
32808
32809/* Shared exit handling for object/array serialization. */
32810DUK_LOCAL void duk__enc_objarr_exit(duk_json_enc_ctx *js_ctx, duk_idx_t *entry_top) {
32811 duk_context *ctx = (duk_context *) js_ctx->thr;
32812 duk_hobject *h_target;
32813
32814 /* C recursion check. */
32815
32816 DUK_ASSERT(js_ctx->recursion_depth > 0);
32817 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
32818 js_ctx->recursion_depth--;
32819
32820 /* Loop check. */
32821
32822 h_target = duk_known_hobject(ctx, *entry_top - 1); /* original target at entry_top - 1 */
32823
32824 if (js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY) {
32825 /* Previous entry was inside visited[], nothing to do. */
32826 } else {
32827 duk_push_sprintf(ctx, DUK_STR_FMT_PTR, (void *) h_target);
32828 duk_del_prop(ctx, js_ctx->idx_loop); /* -> [ ... ] */
32829 }
32830
32831 /* Restore stack top after unbalanced code paths. */
32832 duk_set_top(ctx, *entry_top);
32833
32834 DUK_DDD(DUK_DDDPRINT("shared entry finished: top=%ld, loop=%!T",
32835 (long) duk_get_top(ctx), (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop)));
32836}
32837
32838/* The JO(value) operation: encode object.
32839 *
32840 * Stack policy: [ object ] -> [ object ].
32841 */
32842DUK_LOCAL void duk__enc_object(duk_json_enc_ctx *js_ctx) {
32843 duk_context *ctx = (duk_context *) js_ctx->thr;
32844 duk_hstring *h_key;
32845 duk_idx_t entry_top;
32846 duk_idx_t idx_obj;
32847 duk_idx_t idx_keys;
32848 duk_bool_t emitted;
32849 duk_uarridx_t arr_len, i;
32850 duk_size_t prev_size;
32851
32852 DUK_DDD(DUK_DDDPRINT("duk__enc_object: obj=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
32853
32854 duk__enc_objarr_entry(js_ctx, &entry_top);
32855
32856 idx_obj = entry_top - 1;
32857
32858 if (js_ctx->idx_proplist >= 0) {
32859 idx_keys = js_ctx->idx_proplist;
32860 } else {
32861 /* XXX: would be nice to enumerate an object at specified index */
32862 duk_dup(ctx, idx_obj);
32863 (void) duk_hobject_get_enumerated_keys(ctx, DUK_ENUM_OWN_PROPERTIES_ONLY /*flags*/); /* [ ... target ] -> [ ... target keys ] */
32864 idx_keys = duk_require_normalize_index(ctx, -1);
32865 /* leave stack unbalanced on purpose */
32866 }
32867
32868 DUK_DDD(DUK_DDDPRINT("idx_keys=%ld, h_keys=%!T",
32869 (long) idx_keys, (duk_tval *) duk_get_tval(ctx, idx_keys)));
32870
32871 /* Steps 8-10 have been merged to avoid a "partial" variable. */
32872
32873 DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY);
32874
32875 /* XXX: keys is an internal object with all keys to be processed
32876 * in its (gapless) array part. Because nobody can touch the keys
32877 * object, we could iterate its array part directly (keeping in mind
32878 * that it can be reallocated).
32879 */
32880
32881 arr_len = (duk_uarridx_t) duk_get_length(ctx, idx_keys);
32882 emitted = 0;
32883 for (i = 0; i < arr_len; i++) {
32884 duk_get_prop_index(ctx, idx_keys, i); /* -> [ ... key ] */
32885
32886 DUK_DDD(DUK_DDDPRINT("object property loop: holder=%!T, key=%!T",
32887 (duk_tval *) duk_get_tval(ctx, idx_obj),
32888 (duk_tval *) duk_get_tval(ctx, -1)));
32889
32890 h_key = duk_known_hstring(ctx, -1);
32891 DUK_ASSERT(h_key != NULL);
32892 DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(h_key)); /* proplist filtering; enum options */
32893
32894 prev_size = DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw);
32895 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
32896 duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
32897 duk__enc_key_autoquote(js_ctx, h_key);
32898 DUK__EMIT_2(js_ctx, DUK_ASC_COLON, DUK_ASC_SPACE);
32899 } else {
32900 duk__enc_key_autoquote(js_ctx, h_key);
32901 DUK__EMIT_1(js_ctx, DUK_ASC_COLON);
32902 }
32903
32904 /* [ ... key ] */
32905
32906 if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_obj) == 0)) {
32907 /* Value would yield 'undefined', so skip key altogether.
32908 * Side effects have already happened.
32909 */
32910 DUK_BW_SET_SIZE(js_ctx->thr, &js_ctx->bw, prev_size);
32911 } else {
32912 DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
32913 emitted = 1;
32914 }
32915
32916 /* [ ... ] */
32917 }
32918
32919 if (emitted) {
32920 DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA);
32921 DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
32922 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
32923 DUK_ASSERT(js_ctx->recursion_depth >= 1);
32924 duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1);
32925 }
32926 }
32927 DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
32928
32929 duk__enc_objarr_exit(js_ctx, &entry_top);
32930
32931 DUK_ASSERT_TOP(ctx, entry_top);
32932}
32933
32934/* The JA(value) operation: encode array.
32935 *
32936 * Stack policy: [ array ] -> [ array ].
32937 */
32938DUK_LOCAL void duk__enc_array(duk_json_enc_ctx *js_ctx) {
32939 duk_context *ctx = (duk_context *) js_ctx->thr;
32940 duk_idx_t entry_top;
32941 duk_idx_t idx_arr;
32942 duk_bool_t emitted;
32943 duk_uarridx_t i, arr_len;
32944
32945 DUK_DDD(DUK_DDDPRINT("duk__enc_array: array=%!T",
32946 (duk_tval *) duk_get_tval(ctx, -1)));
32947
32948 duk__enc_objarr_entry(js_ctx, &entry_top);
32949
32950 idx_arr = entry_top - 1;
32951
32952 /* Steps 8-10 have been merged to avoid a "partial" variable. */
32953
32954 DUK__EMIT_1(js_ctx, DUK_ASC_LBRACKET);
32955
32956 arr_len = (duk_uarridx_t) duk_get_length(ctx, idx_arr);
32957 emitted = 0;
32958 for (i = 0; i < arr_len; i++) {
32959 DUK_DDD(DUK_DDDPRINT("array entry loop: array=%!T, index=%ld, arr_len=%ld",
32960 (duk_tval *) duk_get_tval(ctx, idx_arr),
32961 (long) i, (long) arr_len));
32962
32963 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
32964 DUK_ASSERT(js_ctx->recursion_depth >= 1);
32965 duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
32966 }
32967
32968 (void) duk_push_uint_to_hstring(ctx, (duk_uint_t) i); /* -> [ ... key ] */
32969
32970 /* [ ... key ] */
32971
32972 if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_arr) == 0)) {
32973 /* Value would normally be omitted, replace with 'null'. */
32974 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
32975 } else {
32976 ;
32977 }
32978
32979 /* [ ... ] */
32980
32981 DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
32982 emitted = 1;
32983 }
32984
32985 if (emitted) {
32986 DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA);
32987 DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
32988 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
32989 DUK_ASSERT(js_ctx->recursion_depth >= 1);
32990 duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1);
32991 }
32992 }
32993 DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET);
32994
32995 duk__enc_objarr_exit(js_ctx, &entry_top);
32996
32997 DUK_ASSERT_TOP(ctx, entry_top);
32998}
32999
33000/* The Str(key, holder) operation.
33001 *
33002 * Stack policy: [ ... key ] -> [ ... ]
33003 */
33004DUK_LOCAL duk_bool_t duk__enc_value(duk_json_enc_ctx *js_ctx, duk_idx_t idx_holder) {
33005 duk_context *ctx = (duk_context *) js_ctx->thr;
33006 duk_hthread *thr = (duk_hthread *) ctx;
33007 duk_tval *tv;
33008 duk_tval *tv_holder;
33009 duk_tval *tv_key;
33010 duk_small_int_t c;
33011
33012 DUK_DDD(DUK_DDDPRINT("duk__enc_value: idx_holder=%ld, holder=%!T, key=%!T",
33013 (long) idx_holder, (duk_tval *) duk_get_tval(ctx, idx_holder),
33014 (duk_tval *) duk_get_tval(ctx, -1)));
33015
33016 DUK_UNREF(thr);
33017
33018 tv_holder = DUK_GET_TVAL_POSIDX(ctx, idx_holder);
33019 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_holder));
33020 tv_key = DUK_GET_TVAL_NEGIDX(ctx, -1);
33021 DUK_ASSERT(DUK_TVAL_IS_STRING(tv_key));
33022 DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(DUK_TVAL_GET_STRING(tv_key))); /* Caller responsible. */
33023 (void) duk_hobject_getprop(thr, tv_holder, tv_key);
33024
33025 /* -> [ ... key val ] */
33026
33027 DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
33028
33029 /* Standard JSON checks for .toJSON() only for actual objects; for
33030 * example, setting Number.prototype.toJSON and then serializing a
33031 * number won't invoke the .toJSON() method. However, lightfuncs and
33032 * plain buffers mimic objects so we check for their .toJSON() method.
33033 */
33034 if (duk_check_type_mask(ctx, -1, DUK_TYPE_MASK_OBJECT |
33035 DUK_TYPE_MASK_LIGHTFUNC |
33036 DUK_TYPE_MASK_BUFFER)) {
33037 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_TO_JSON);
33038 if (duk_is_callable(ctx, -1)) { /* toJSON() can also be a lightfunc */
33039 DUK_DDD(DUK_DDDPRINT("value is object, has callable toJSON() -> call it"));
33040 /* XXX: duk_dup_unvalidated(ctx, -2) etc. */
33041 duk_dup_m2(ctx); /* -> [ ... key val toJSON val ] */
33042 duk_dup_m4(ctx); /* -> [ ... key val toJSON val key ] */
33043 duk_call_method(ctx, 1); /* -> [ ... key val val' ] */
33044 duk_remove_m2(ctx); /* -> [ ... key val' ] */
33045 } else {
33046 duk_pop(ctx); /* -> [ ... key val ] */
33047 }
33048 }
33049
33050 /* [ ... key val ] */
33051
33052 DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
33053
33054 if (js_ctx->h_replacer) {
33055 /* XXX: Here a "slice copy" would be useful. */
33056 DUK_DDD(DUK_DDDPRINT("replacer is set, call replacer"));
33057 duk_push_hobject(ctx, js_ctx->h_replacer); /* -> [ ... key val replacer ] */
33058 duk_dup(ctx, idx_holder); /* -> [ ... key val replacer holder ] */
33059 duk_dup_m4(ctx); /* -> [ ... key val replacer holder key ] */
33060 duk_dup_m4(ctx); /* -> [ ... key val replacer holder key val ] */
33061 duk_call_method(ctx, 2); /* -> [ ... key val val' ] */
33062 duk_remove_m2(ctx); /* -> [ ... key val' ] */
33063 }
33064
33065 /* [ ... key val ] */
33066
33067 DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
33068
33069 tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
33070 if (DUK_TVAL_IS_OBJECT(tv)) {
33071 duk_hobject *h;
33072
33073 h = DUK_TVAL_GET_OBJECT(tv);
33074 DUK_ASSERT(h != NULL);
33075
33076#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
33077#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
33078 if (DUK_HOBJECT_IS_BUFOBJ(h) &&
33079 js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE)) {
33080 /* With JX/JC a bufferobject gets serialized specially. */
33081 duk_hbufobj *h_bufobj;
33082 h_bufobj = (duk_hbufobj *) h;
33083 DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
33084 duk__enc_bufobj(js_ctx, h_bufobj);
33085 goto pop2_emitted;
33086 }
33087 /* Otherwise bufferobjects get serialized as normal objects. */
33088#endif /* JX || JC */
33089#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
33090 c = (duk_small_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h);
33091 switch (c) {
33092 case DUK_HOBJECT_CLASS_NUMBER: {
33093 DUK_DDD(DUK_DDDPRINT("value is a Number object -> coerce with ToNumber()"));
33094 duk_to_number_m1(ctx);
33095 /* The coercion potentially invokes user .valueOf() and .toString()
33096 * but can't result in a function value because ToPrimitive() would
33097 * reject such a result: test-dev-json-stringify-coercion-1.js.
33098 */
33099 DUK_ASSERT(!duk_is_callable(ctx, -1));
33100 break;
33101 }
33102 case DUK_HOBJECT_CLASS_STRING: {
33103 DUK_DDD(DUK_DDDPRINT("value is a String object -> coerce with ToString()"));
33104 duk_to_string(ctx, -1);
33105 /* Same coercion behavior as for Number. */
33106 DUK_ASSERT(!duk_is_callable(ctx, -1));
33107 break;
33108 }
33109#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
33110 case DUK_HOBJECT_CLASS_POINTER:
33111#endif
33112 case DUK_HOBJECT_CLASS_BOOLEAN: {
33113 DUK_DDD(DUK_DDDPRINT("value is a Boolean/Buffer/Pointer object -> get internal value"));
33114 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_VALUE);
33115 duk_remove_m2(ctx);
33116 break;
33117 }
33118 default: {
33119 /* Normal object which doesn't get automatically coerced to a
33120 * primitive value. Functions are checked for specially. The
33121 * primitive value coercions for Number, String, Pointer, and
33122 * Boolean can't result in functions so suffices to check here.
33123 * Symbol objects are handled like plain objects (their primitive
33124 * value is NOT looked up like for e.g. String objects).
33125 */
33126 DUK_ASSERT(h != NULL);
33127 if (DUK_HOBJECT_IS_CALLABLE(h)) {
33128#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
33129 if (js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM |
33130 DUK_JSON_FLAG_EXT_COMPATIBLE)) {
33131 /* We only get here when doing non-standard JSON encoding */
33132 DUK_DDD(DUK_DDDPRINT("-> function allowed, serialize to custom format"));
33133 DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible);
33134 DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function);
33135 goto pop2_emitted;
33136 } else {
33137 DUK_DDD(DUK_DDDPRINT("-> will result in undefined (function)"));
33138 goto pop2_undef;
33139 }
33140#else /* DUK_USE_JX || DUK_USE_JC */
33141 DUK_DDD(DUK_DDDPRINT("-> will result in undefined (function)"));
33142 goto pop2_undef;
33143#endif /* DUK_USE_JX || DUK_USE_JC */
33144 }
33145 }
33146 } /* end switch */
33147 }
33148
33149 /* [ ... key val ] */
33150
33151 DUK_DDD(DUK_DDDPRINT("value=%!T", (duk_tval *) duk_get_tval(ctx, -1)));
33152
33153 if (duk_check_type_mask(ctx, -1, js_ctx->mask_for_undefined)) {
33154 /* will result in undefined */
33155 DUK_DDD(DUK_DDDPRINT("-> will result in undefined (type mask check)"));
33156 goto pop2_undef;
33157 }
33158 tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
33159
33160 switch (DUK_TVAL_GET_TAG(tv)) {
33161#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
33162 /* When JX/JC not in use, the type mask above will avoid this case if needed. */
33163 case DUK_TAG_UNDEFINED: {
33164 DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined);
33165 break;
33166 }
33167#endif
33168 case DUK_TAG_NULL: {
33169 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
33170 break;
33171 }
33172 case DUK_TAG_BOOLEAN: {
33173 DUK__EMIT_STRIDX(js_ctx, DUK_TVAL_GET_BOOLEAN(tv) ?
33174 DUK_STRIDX_TRUE : DUK_STRIDX_FALSE);
33175 break;
33176 }
33177#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
33178 /* When JX/JC not in use, the type mask above will avoid this case if needed. */
33179 case DUK_TAG_POINTER: {
33180 duk__enc_pointer(js_ctx, DUK_TVAL_GET_POINTER(tv));
33181 break;
33182 }
33183#endif /* DUK_USE_JX || DUK_USE_JC */
33184 case DUK_TAG_STRING: {
33185 duk_hstring *h = DUK_TVAL_GET_STRING(tv);
33186 DUK_ASSERT(h != NULL);
33187 if (DUK_HSTRING_HAS_SYMBOL(h)) {
33188 goto pop2_undef;
33189 }
33190 duk__enc_quote_string(js_ctx, h);
33191 break;
33192 }
33193 case DUK_TAG_OBJECT: {
33194 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
33195 DUK_ASSERT(h != NULL);
33196
33197 /* Function values are handled completely above (including
33198 * coercion results):
33199 */
33200 DUK_ASSERT(!DUK_HOBJECT_IS_CALLABLE(h));
33201
33202 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) {
33203 duk__enc_array(js_ctx);
33204 } else {
33205 duk__enc_object(js_ctx);
33206 }
33207 break;
33208 }
33209 /* Because plain buffers mimics Uint8Array, they have enumerable
33210 * index properties [0,byteLength[. Because JSON only serializes
33211 * enumerable own properties, no properties can be serialized for
33212 * plain buffers (all virtual properties are non-enumerable). However,
33213 * there may be a .toJSON() method which was already handled above.
33214 */
33215 case DUK_TAG_BUFFER: {
33216#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
33217 if (js_ctx->flag_ext_custom_or_compatible) {
33218 duk__enc_buffer(js_ctx, DUK_TVAL_GET_BUFFER(tv));
33219 break;
33220 }
33221#endif
33222 /* Could implement a fast path, but object coerce and
33223 * serialize the result for now.
33224 */
33225 duk_to_object(ctx, -1);
33226 duk__enc_object(js_ctx);
33227 break;
33228 }
33229 case DUK_TAG_LIGHTFUNC: {
33230#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
33231 /* We only get here when doing non-standard JSON encoding */
33232 DUK_ASSERT(js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible);
33233 DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function);
33234#else
33235 /* Standard JSON omits functions */
33236 DUK_UNREACHABLE();
33237#endif
33238 break;
33239 }
33240#if defined(DUK_USE_FASTINT)
33241 case DUK_TAG_FASTINT:
33242 /* Number serialization has a significant impact relative to
33243 * other fast path code, so careful fast path for fastints.
33244 */
33245 duk__enc_fastint_tval(js_ctx, tv);
33246 break;
33247#endif
33248 default: {
33249 /* number */
33250 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
33251 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
33252 /* XXX: A fast path for usual integers would be useful when
33253 * fastint support is not enabled.
33254 */
33255 duk__enc_double(js_ctx);
33256 break;
33257 }
33258 }
33259
33260#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
33261 pop2_emitted:
33262#endif
33263 duk_pop_2(ctx); /* [ ... key val ] -> [ ... ] */
33264 return 1; /* emitted */
33265
33266 pop2_undef:
33267 duk_pop_2(ctx); /* [ ... key val ] -> [ ... ] */
33268 return 0; /* not emitted */
33269}
33270
33271/* E5 Section 15.12.3, main algorithm, step 4.b.ii steps 1-4. */
33272DUK_LOCAL duk_bool_t duk__enc_allow_into_proplist(duk_tval *tv) {
33273 duk_small_int_t c;
33274
33275 /* XXX: some kind of external internal type checker?
33276 * - type mask; symbol flag; class mask
33277 */
33278 DUK_ASSERT(tv != NULL);
33279 if (DUK_TVAL_IS_STRING(tv)) {
33280 duk_hstring *h;
33281 h = DUK_TVAL_GET_STRING(tv);
33282 DUK_ASSERT(h != NULL);
33283 if (DUK_HSTRING_HAS_SYMBOL(h)) {
33284 return 0;
33285 }
33286 return 1;
33287 } else if (DUK_TVAL_IS_NUMBER(tv)) {
33288 return 1;
33289 } else if (DUK_TVAL_IS_OBJECT(tv)) {
33290 duk_hobject *h;
33291 h = DUK_TVAL_GET_OBJECT(tv);
33292 DUK_ASSERT(h != NULL);
33293 c = (duk_small_int_t) DUK_HOBJECT_GET_CLASS_NUMBER(h);
33294 if (c == DUK_HOBJECT_CLASS_STRING || c == DUK_HOBJECT_CLASS_NUMBER) {
33295 return 1;
33296 }
33297 }
33298
33299 return 0;
33300}
33301
33302/*
33303 * JSON.stringify() fast path
33304 *
33305 * Otherwise supports full JSON, JX, and JC features, but bails out on any
33306 * possible side effect which might change the value being serialized. The
33307 * fast path can take advantage of the fact that the value being serialized
33308 * is unchanged so that we can walk directly through property tables etc.
33309 */
33310
33311#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
33312DUK_LOCAL duk_bool_t duk__json_stringify_fast_value(duk_json_enc_ctx *js_ctx, duk_tval *tv) {
33313 duk_uint_fast32_t i, n;
33314
33315 DUK_DDD(DUK_DDDPRINT("stringify fast: %!T", tv));
33316
33317 DUK_ASSERT(js_ctx != NULL);
33318 DUK_ASSERT(js_ctx->thr != NULL);
33319
33320#if 0 /* disabled for now */
33321 restart_match:
33322#endif
33323
33324 DUK_ASSERT(tv != NULL);
33325
33326 switch (DUK_TVAL_GET_TAG(tv)) {
33327 case DUK_TAG_UNDEFINED: {
33328#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
33329 if (js_ctx->flag_ext_custom || js_ctx->flag_ext_compatible) {
33330 DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined);
33331 break;
33332 } else {
33333 goto emit_undefined;
33334 }
33335#else
33336 goto emit_undefined;
33337#endif
33338 }
33339 case DUK_TAG_NULL: {
33340 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
33341 break;
33342 }
33343 case DUK_TAG_BOOLEAN: {
33344 DUK__EMIT_STRIDX(js_ctx, DUK_TVAL_GET_BOOLEAN(tv) ?
33345 DUK_STRIDX_TRUE : DUK_STRIDX_FALSE);
33346 break;
33347 }
33348 case DUK_TAG_STRING: {
33349 duk_hstring *h;
33350 h = DUK_TVAL_GET_STRING(tv);
33351 DUK_ASSERT(h != NULL);
33352 if (DUK_HSTRING_HAS_SYMBOL(h)) {
33353 goto emit_undefined;
33354 }
33355 duk__enc_quote_string(js_ctx, h);
33356 break;
33357 }
33358 case DUK_TAG_OBJECT: {
33359 duk_hobject *obj;
33360 duk_tval *tv_val;
33361 duk_bool_t emitted = 0;
33362 duk_uint32_t c_bit, c_all, c_array, c_unbox, c_undef,
33363 c_func, c_bufobj, c_object, c_abort;
33364
33365 /* For objects JSON.stringify() only looks for own, enumerable
33366 * properties which is nice for the fast path here.
33367 *
33368 * For arrays JSON.stringify() uses [[Get]] so it will actually
33369 * inherit properties during serialization! This fast path
33370 * supports gappy arrays as long as there's no actual inherited
33371 * property (which might be a getter etc).
33372 *
33373 * Since recursion only happens for objects, we can have both
33374 * recursion and loop checks here. We use a simple, depth-limited
33375 * loop check in the fast path because the object-based tracking
33376 * is very slow (when tested, it accounted for 50% of fast path
33377 * execution time for input data with a lot of small objects!).
33378 */
33379
33380 /* XXX: for real world code, could just ignore array inheritance
33381 * and only look at array own properties.
33382 */
33383
33384 /* We rely on a few object flag / class number relationships here,
33385 * assert for them.
33386 */
33387
33388 obj = DUK_TVAL_GET_OBJECT(tv);
33389 DUK_ASSERT(obj != NULL);
33390 DUK_ASSERT_HOBJECT_VALID(obj);
33391
33392 /* Once recursion depth is increased, exit path must decrease
33393 * it (though it's OK to abort the fast path).
33394 */
33395
33396 DUK_ASSERT(js_ctx->recursion_depth >= 0);
33397 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
33398 if (js_ctx->recursion_depth >= js_ctx->recursion_limit) {
33399 DUK_DD(DUK_DDPRINT("fast path recursion limit"));
33400 DUK_ERROR_RANGE(js_ctx->thr, DUK_STR_JSONDEC_RECLIMIT);
33401 }
33402
33403 for (i = 0, n = (duk_uint_fast32_t) js_ctx->recursion_depth; i < n; i++) {
33404 if (DUK_UNLIKELY(js_ctx->visiting[i] == obj)) {
33405 DUK_DD(DUK_DDPRINT("fast path loop detect"));
33406 DUK_ERROR_TYPE(js_ctx->thr, DUK_STR_CYCLIC_INPUT);
33407 }
33408 }
33409
33410 /* Guaranteed by recursion_limit setup so we don't have to
33411 * check twice.
33412 */
33413 DUK_ASSERT(js_ctx->recursion_depth < DUK_JSON_ENC_LOOPARRAY);
33414 js_ctx->visiting[js_ctx->recursion_depth] = obj;
33415 js_ctx->recursion_depth++;
33416
33417 /* If object has a .toJSON() property, we can't be certain
33418 * that it wouldn't mutate any value arbitrarily, so bail
33419 * out of the fast path.
33420 *
33421 * If an object is a Proxy we also can't avoid side effects
33422 * so abandon.
33423 */
33424 /* XXX: non-callable .toJSON() doesn't need to cause an abort
33425 * but does at the moment, probably not worth fixing.
33426 */
33427 if (duk_hobject_hasprop_raw(js_ctx->thr, obj, DUK_HTHREAD_STRING_TO_JSON(js_ctx->thr)) ||
33428 DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj)) {
33429 DUK_DD(DUK_DDPRINT("object has a .toJSON property or object is a Proxy, abort fast path"));
33430 goto abort_fastpath;
33431 }
33432
33433 /* We could use a switch-case for the class number but it turns out
33434 * a small if-else ladder on class masks is better. The if-ladder
33435 * should be in order of relevancy.
33436 */
33437
33438 /* XXX: move masks to js_ctx? they don't change during one
33439 * fast path invocation.
33440 */
33441 DUK_ASSERT(DUK_HOBJECT_CLASS_MAX <= 31);
33442#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
33443 if (js_ctx->flag_ext_custom_or_compatible) {
33444 c_all = DUK_HOBJECT_CMASK_ALL;
33445 c_array = DUK_HOBJECT_CMASK_ARRAY;
33446 c_unbox = DUK_HOBJECT_CMASK_NUMBER |
33447 DUK_HOBJECT_CMASK_STRING |
33448 DUK_HOBJECT_CMASK_BOOLEAN |
33449 DUK_HOBJECT_CMASK_POINTER; /* Symbols are not unboxed. */
33450 c_func = DUK_HOBJECT_CMASK_FUNCTION;
33451 c_bufobj = DUK_HOBJECT_CMASK_ALL_BUFOBJS;
33452 c_undef = 0;
33453 c_abort = 0;
33454 c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef | c_abort);
33455 }
33456 else
33457#endif
33458 {
33459 c_all = DUK_HOBJECT_CMASK_ALL;
33460 c_array = DUK_HOBJECT_CMASK_ARRAY;
33461 c_unbox = DUK_HOBJECT_CMASK_NUMBER |
33462 DUK_HOBJECT_CMASK_STRING |
33463 DUK_HOBJECT_CMASK_BOOLEAN; /* Symbols are not unboxed. */
33464 c_func = 0;
33465 c_bufobj = 0;
33466 c_undef = DUK_HOBJECT_CMASK_FUNCTION |
33467 DUK_HOBJECT_CMASK_POINTER;
33468 /* As the fast path doesn't currently properly support
33469 * duk_hbufobj virtual properties, abort fast path if
33470 * we encounter them in plain JSON mode.
33471 */
33472 c_abort = DUK_HOBJECT_CMASK_ALL_BUFOBJS;
33473 c_object = c_all & ~(c_array | c_unbox | c_func | c_bufobj | c_undef | c_abort);
33474 }
33475
33476 c_bit = DUK_HOBJECT_GET_CLASS_MASK(obj);
33477 if (c_bit & c_object) {
33478 /* All other object types. */
33479 DUK__EMIT_1(js_ctx, DUK_ASC_LCURLY);
33480
33481 /* A non-Array object should not have an array part in practice.
33482 * But since it is supported internally (and perhaps used at some
33483 * point), check and abandon if that's the case.
33484 */
33485 if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
33486 DUK_DD(DUK_DDPRINT("non-Array object has array part, abort fast path"));
33487 goto abort_fastpath;
33488 }
33489
33490 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(obj); i++) {
33491 duk_hstring *k;
33492 duk_size_t prev_size;
33493
33494 k = DUK_HOBJECT_E_GET_KEY(js_ctx->thr->heap, obj, i);
33495 if (!k) {
33496 continue;
33497 }
33498 if (DUK_HSTRING_HAS_ARRIDX(k)) {
33499 /* If an object has array index keys we would need
33500 * to sort them into the ES2015 enumeration order to
33501 * be consistent with the slow path. Abort the fast
33502 * path and handle in the slow path for now.
33503 */
33504 DUK_DD(DUK_DDPRINT("property key is an array index, abort fast path"));
33505 goto abort_fastpath;
33506 }
33507 if (!DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(js_ctx->thr->heap, obj, i)) {
33508 continue;
33509 }
33510 if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(js_ctx->thr->heap, obj, i)) {
33511 /* Getter might have arbitrary side effects,
33512 * so bail out.
33513 */
33514 DUK_DD(DUK_DDPRINT("property is an accessor, abort fast path"));
33515 goto abort_fastpath;
33516 }
33517 if (DUK_HSTRING_HAS_SYMBOL(k)) {
33518 continue;
33519 }
33520
33521 tv_val = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(js_ctx->thr->heap, obj, i);
33522
33523 prev_size = DUK_BW_GET_SIZE(js_ctx->thr, &js_ctx->bw);
33524 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
33525 duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
33526 duk__enc_key_autoquote(js_ctx, k);
33527 DUK__EMIT_2(js_ctx, DUK_ASC_COLON, DUK_ASC_SPACE);
33528 } else {
33529 duk__enc_key_autoquote(js_ctx, k);
33530 DUK__EMIT_1(js_ctx, DUK_ASC_COLON);
33531 }
33532
33533 if (duk__json_stringify_fast_value(js_ctx, tv_val) == 0) {
33534 DUK_DD(DUK_DDPRINT("prop value not supported, rewind key and colon"));
33535 DUK_BW_SET_SIZE(js_ctx->thr, &js_ctx->bw, prev_size);
33536 } else {
33537 DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
33538 emitted = 1;
33539 }
33540 }
33541
33542 /* If any non-Array value had enumerable virtual own
33543 * properties, they should be serialized here (actually,
33544 * before the explicit properties). Standard types don't.
33545 */
33546
33547 if (emitted) {
33548 DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA);
33549 DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
33550 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
33551 DUK_ASSERT(js_ctx->recursion_depth >= 1);
33552 duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1);
33553 }
33554 }
33555 DUK__EMIT_1(js_ctx, DUK_ASC_RCURLY);
33556 } else if (c_bit & c_array) {
33557 duk_uint_fast32_t arr_len;
33558 duk_uint_fast32_t asize;
33559
33560 DUK__EMIT_1(js_ctx, DUK_ASC_LBRACKET);
33561
33562 /* Assume arrays are dense in the fast path. */
33563 if (!DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
33564 DUK_DD(DUK_DDPRINT("Array object is sparse, abort fast path"));
33565 goto abort_fastpath;
33566 }
33567
33568 arr_len = (duk_uint_fast32_t) ((duk_harray *) obj)->length;
33569 asize = (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(obj);
33570 /* Array part may be larger than 'length'; if so, iterate
33571 * only up to array 'length'. Array part may also be smaller
33572 * than 'length' in some cases.
33573 */
33574 for (i = 0; i < arr_len; i++) {
33575 duk_tval *tv_arrval;
33576 duk_hstring *h_tmp;
33577 duk_bool_t has_inherited;
33578
33579 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
33580 duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth);
33581 }
33582
33583 if (DUK_LIKELY(i < asize)) {
33584 tv_arrval = DUK_HOBJECT_A_GET_VALUE_PTR(js_ctx->thr->heap, obj, i);
33585 if (DUK_LIKELY(!DUK_TVAL_IS_UNUSED(tv_arrval))) {
33586 /* Expected case: element is present. */
33587 if (duk__json_stringify_fast_value(js_ctx, tv_arrval) == 0) {
33588 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
33589 }
33590 goto elem_done;
33591 }
33592 }
33593
33594 /* Gap in array; check for inherited property,
33595 * bail out if one exists. This should be enough
33596 * to support gappy arrays for all practical code.
33597 */
33598
33599 h_tmp = duk_push_uint_to_hstring((duk_context *) js_ctx->thr, (duk_uint_t) i);
33600 has_inherited = duk_hobject_hasprop_raw(js_ctx->thr, obj, h_tmp);
33601 duk_pop((duk_context *) js_ctx->thr);
33602 if (has_inherited) {
33603 DUK_D(DUK_DPRINT("gap in array, conflicting inherited property, abort fast path"));
33604 goto abort_fastpath;
33605 }
33606
33607 /* Ordinary gap, undefined encodes to 'null' in
33608 * standard JSON, but JX/JC use their form for
33609 * undefined to better preserve the typing.
33610 */
33611 DUK_D(DUK_DPRINT("gap in array, no conflicting inherited property, remain on fast path"));
33612#if defined(DUK_USE_JX)
33613 DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_undefined);
33614#else
33615 DUK__EMIT_STRIDX(js_ctx, DUK_STRIDX_LC_NULL);
33616#endif
33617 /* fall through */
33618
33619 elem_done:
33620 DUK__EMIT_1(js_ctx, DUK_ASC_COMMA);
33621 emitted = 1;
33622 }
33623
33624 if (emitted) {
33625 DUK_ASSERT(*((duk_uint8_t *) DUK_BW_GET_PTR(js_ctx->thr, &js_ctx->bw) - 1) == DUK_ASC_COMMA);
33626 DUK__UNEMIT_1(js_ctx); /* eat trailing comma */
33627 if (DUK_UNLIKELY(js_ctx->h_gap != NULL)) {
33628 DUK_ASSERT(js_ctx->recursion_depth >= 1);
33629 duk__enc_newline_indent(js_ctx, js_ctx->recursion_depth - 1);
33630 }
33631 }
33632 DUK__EMIT_1(js_ctx, DUK_ASC_RBRACKET);
33633 } else if (c_bit & c_unbox) {
33634 /* Certain boxed types are required to go through
33635 * automatic unboxing. Rely on internal value being
33636 * sane (to avoid infinite recursion).
33637 */
33638 DUK_ASSERT((c_bit & DUK_HOBJECT_CMASK_SYMBOL) == 0); /* Symbols are not unboxed. */
33639
33640#if 1
33641 /* The code below is incorrect if .toString() or .valueOf() have
33642 * have been overridden. The correct approach would be to look up
33643 * the method(s) and if they resolve to the built-in function we
33644 * can safely bypass it and look up the internal value directly.
33645 * Unimplemented for now, abort fast path for boxed values.
33646 */
33647 goto abort_fastpath;
33648#else /* disabled */
33649 /* Disabled until fixed, see above. */
33650 duk_tval *tv_internal;
33651
33652 DUK_DD(DUK_DDPRINT("auto unboxing in fast path"));
33653
33654 tv_internal = duk_hobject_get_internal_value_tval_ptr(js_ctx->thr->heap, obj);
33655 DUK_ASSERT(tv_internal != NULL);
33656 DUK_ASSERT(DUK_TVAL_IS_STRING(tv_internal) ||
33657 DUK_TVAL_IS_NUMBER(tv_internal) ||
33658 DUK_TVAL_IS_BOOLEAN(tv_internal) ||
33659 DUK_TVAL_IS_POINTER(tv_internal));
33660
33661 tv = tv_internal;
33662 DUK_ASSERT(js_ctx->recursion_depth > 0);
33663 js_ctx->recursion_depth--; /* required to keep recursion depth correct */
33664 goto restart_match;
33665#endif /* disabled */
33666#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
33667 } else if (c_bit & c_func) {
33668 DUK__EMIT_STRIDX(js_ctx, js_ctx->stridx_custom_function);
33669#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
33670 } else if (c_bit & c_bufobj) {
33671 duk__enc_bufobj(js_ctx, (duk_hbufobj *) obj);
33672#endif
33673#endif
33674 } else if (c_bit & c_abort) {
33675 DUK_DD(DUK_DDPRINT("abort fast path for unsupported type"));
33676 goto abort_fastpath;
33677 } else {
33678 DUK_ASSERT((c_bit & c_undef) != 0);
33679
33680 /* Must decrease recursion depth before returning. */
33681 DUK_ASSERT(js_ctx->recursion_depth > 0);
33682 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
33683 js_ctx->recursion_depth--;
33684 goto emit_undefined;
33685 }
33686
33687 DUK_ASSERT(js_ctx->recursion_depth > 0);
33688 DUK_ASSERT(js_ctx->recursion_depth <= js_ctx->recursion_limit);
33689 js_ctx->recursion_depth--;
33690 break;
33691 }
33692 case DUK_TAG_BUFFER: {
33693 /* Plain buffers are treated like Uint8Arrays: they have
33694 * enumerable indices. Other virtual properties are not
33695 * enumerable, and inherited properties are not serialized.
33696 * However, there can be a replacer (not relevant here) or
33697 * a .toJSON() method (which we need to check for explicitly).
33698 */
33699
33700#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
33701 if (duk_hobject_hasprop_raw(js_ctx->thr,
33702 js_ctx->thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE],
33703 DUK_HTHREAD_STRING_TO_JSON(js_ctx->thr))) {
33704 DUK_DD(DUK_DDPRINT("value is a plain buffer and there's an inherited .toJSON, abort fast path"));
33705 goto abort_fastpath;
33706 }
33707#endif
33708
33709#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
33710 if (js_ctx->flag_ext_custom_or_compatible) {
33711 duk__enc_buffer(js_ctx, DUK_TVAL_GET_BUFFER(tv));
33712 break;
33713 }
33714#endif
33715 /* Could implement a fast path, but abort fast path for now. */
33716 DUK_DD(DUK_DDPRINT("value is a plain buffer and serializing as plain JSON, abort fast path"));
33717 goto abort_fastpath;
33718 }
33719 case DUK_TAG_POINTER: {
33720#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
33721 if (js_ctx->flag_ext_custom_or_compatible) {
33722 duk__enc_pointer(js_ctx, DUK_TVAL_GET_POINTER(tv));
33723 break;
33724 } else {
33725 goto emit_undefined;
33726 }
33727#else
33728 goto emit_undefined;
33729#endif
33730 }
33731 case DUK_TAG_LIGHTFUNC: {
33732 /* A lightfunc might also inherit a .toJSON() so just bail out. */
33733 /* XXX: Could just lookup .toJSON() and continue in fast path,
33734 * as it would almost never be defined.
33735 */
33736 DUK_DD(DUK_DDPRINT("value is a lightfunc, abort fast path"));
33737 goto abort_fastpath;
33738 }
33739#if defined(DUK_USE_FASTINT)
33740 case DUK_TAG_FASTINT: {
33741 /* Number serialization has a significant impact relative to
33742 * other fast path code, so careful fast path for fastints.
33743 */
33744 duk__enc_fastint_tval(js_ctx, tv);
33745 break;
33746 }
33747#endif
33748 default: {
33749 /* XXX: A fast path for usual integers would be useful when
33750 * fastint support is not enabled.
33751 */
33752 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
33753 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
33754
33755 /* XXX: Stack discipline is annoying, could be changed in numconv. */
33756 duk_push_tval((duk_context *) js_ctx->thr, tv);
33757 duk__enc_double(js_ctx);
33758 duk_pop((duk_context *) js_ctx->thr);
33759
33760#if 0
33761 /* Could also rely on native sprintf(), but it will handle
33762 * values like NaN, Infinity, -0, exponent notation etc in
33763 * a JSON-incompatible way.
33764 */
33765 duk_double_t d;
33766 char buf[64];
33767
33768 DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
33769 d = DUK_TVAL_GET_DOUBLE(tv);
33770 DUK_SPRINTF(buf, "%lg", d);
33771 DUK__EMIT_CSTR(js_ctx, buf);
33772#endif
33773 }
33774 }
33775 return 1; /* not undefined */
33776
33777 emit_undefined:
33778 return 0; /* value was undefined/unsupported */
33779
33780 abort_fastpath:
33781 /* Error message doesn't matter: the error is ignored anyway. */
33782 DUK_DD(DUK_DDPRINT("aborting fast path"));
33783 DUK_ERROR_INTERNAL(js_ctx->thr);
33784 return 0; /* unreachable */
33785}
33786
33787DUK_LOCAL duk_ret_t duk__json_stringify_fast(duk_context *ctx, void *udata) {
33788 duk_json_enc_ctx *js_ctx;
33789 duk_tval *tv;
33790
33791 DUK_ASSERT(ctx != NULL);
33792 DUK_ASSERT(udata != NULL);
33793
33794 js_ctx = (duk_json_enc_ctx *) udata;
33795 DUK_ASSERT(js_ctx != NULL);
33796
33797 tv = DUK_GET_TVAL_NEGIDX(ctx, -1);
33798 if (duk__json_stringify_fast_value(js_ctx, tv) == 0) {
33799 DUK_DD(DUK_DDPRINT("top level value not supported, fail fast path"));
33800 DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx); /* Error message is ignored, so doesn't matter. */
33801 }
33802
33803 return 0;
33804}
33805#endif /* DUK_USE_JSON_STRINGIFY_FASTPATH */
33806
33807/*
33808 * Top level wrappers
33809 */
33810
33811DUK_INTERNAL
33812void duk_bi_json_parse_helper(duk_context *ctx,
33813 duk_idx_t idx_value,
33814 duk_idx_t idx_reviver,
33815 duk_small_uint_t flags) {
33816 duk_hthread *thr = (duk_hthread *) ctx;
33817 duk_json_dec_ctx js_ctx_alloc;
33818 duk_json_dec_ctx *js_ctx = &js_ctx_alloc;
33819 duk_hstring *h_text;
33820#if defined(DUK_USE_ASSERTIONS)
33821 duk_idx_t entry_top = duk_get_top(ctx);
33822#endif
33823
33824 /* negative top-relative indices not allowed now */
33825 DUK_ASSERT(idx_value == DUK_INVALID_INDEX || idx_value >= 0);
33826 DUK_ASSERT(idx_reviver == DUK_INVALID_INDEX || idx_reviver >= 0);
33827
33828 DUK_DDD(DUK_DDDPRINT("JSON parse start: text=%!T, reviver=%!T, flags=0x%08lx, stack_top=%ld",
33829 (duk_tval *) duk_get_tval(ctx, idx_value),
33830 (duk_tval *) duk_get_tval(ctx, idx_reviver),
33831 (unsigned long) flags,
33832 (long) duk_get_top(ctx)));
33833
33834 DUK_MEMZERO(&js_ctx_alloc, sizeof(js_ctx_alloc));
33835 js_ctx->thr = thr;
33836#if defined(DUK_USE_EXPLICIT_NULL_INIT)
33837 /* nothing now */
33838#endif
33839 js_ctx->recursion_limit = DUK_USE_JSON_DEC_RECLIMIT;
33840 DUK_ASSERT(js_ctx->recursion_depth == 0);
33841
33842 /* Flag handling currently assumes that flags are consistent. This is OK
33843 * because the call sites are now strictly controlled.
33844 */
33845
33846 js_ctx->flags = flags;
33847#if defined(DUK_USE_JX)
33848 js_ctx->flag_ext_custom = flags & DUK_JSON_FLAG_EXT_CUSTOM;
33849#endif
33850#if defined(DUK_USE_JC)
33851 js_ctx->flag_ext_compatible = flags & DUK_JSON_FLAG_EXT_COMPATIBLE;
33852#endif
33853#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
33854 js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE);
33855#endif
33856
33857 h_text = duk_to_hstring(ctx, idx_value); /* coerce in-place; rejects Symbols */
33858 DUK_ASSERT(h_text != NULL);
33859
33860 /* JSON parsing code is allowed to read [p_start,p_end]: p_end is
33861 * valid and points to the string NUL terminator (which is always
33862 * guaranteed for duk_hstrings.
33863 */
33864 js_ctx->p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text);
33865 js_ctx->p = js_ctx->p_start;
33866 js_ctx->p_end = ((const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_text)) +
33867 DUK_HSTRING_GET_BYTELEN(h_text);
33868 DUK_ASSERT(*(js_ctx->p_end) == 0x00);
33869
33870 duk__dec_value(js_ctx); /* -> [ ... value ] */
33871
33872 /* Trailing whitespace has been eaten by duk__dec_value(), so if
33873 * we're not at end of input here, it's a SyntaxError.
33874 */
33875
33876 if (js_ctx->p != js_ctx->p_end) {
33877 duk__dec_syntax_error(js_ctx);
33878 }
33879
33880 if (duk_is_callable(ctx, idx_reviver)) {
33881 DUK_DDD(DUK_DDDPRINT("applying reviver: %!T",
33882 (duk_tval *) duk_get_tval(ctx, idx_reviver)));
33883
33884 js_ctx->idx_reviver = idx_reviver;
33885
33886 duk_push_object(ctx);
33887 duk_dup_m2(ctx); /* -> [ ... val root val ] */
33888 duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_EMPTY_STRING); /* default attrs ok */
33889 duk_push_hstring_stridx(ctx, DUK_STRIDX_EMPTY_STRING); /* -> [ ... val root "" ] */
33890
33891 DUK_DDD(DUK_DDDPRINT("start reviver walk, root=%!T, name=%!T",
33892 (duk_tval *) duk_get_tval(ctx, -2),
33893 (duk_tval *) duk_get_tval(ctx, -1)));
33894
33895 duk__dec_reviver_walk(js_ctx); /* [ ... val root "" ] -> [ ... val val' ] */
33896 duk_remove_m2(ctx); /* -> [ ... val' ] */
33897 } else {
33898 DUK_DDD(DUK_DDDPRINT("reviver does not exist or is not callable: %!T",
33899 (duk_tval *) duk_get_tval(ctx, idx_reviver)));
33900 }
33901
33902 /* Final result is at stack top. */
33903
33904 DUK_DDD(DUK_DDDPRINT("JSON parse end: text=%!T, reviver=%!T, flags=0x%08lx, result=%!T, stack_top=%ld",
33905 (duk_tval *) duk_get_tval(ctx, idx_value),
33906 (duk_tval *) duk_get_tval(ctx, idx_reviver),
33907 (unsigned long) flags,
33908 (duk_tval *) duk_get_tval(ctx, -1),
33909 (long) duk_get_top(ctx)));
33910
33911 DUK_ASSERT(duk_get_top(ctx) == entry_top + 1);
33912}
33913
33914DUK_INTERNAL
33915void duk_bi_json_stringify_helper(duk_context *ctx,
33916 duk_idx_t idx_value,
33917 duk_idx_t idx_replacer,
33918 duk_idx_t idx_space,
33919 duk_small_uint_t flags) {
33920 duk_hthread *thr = (duk_hthread *) ctx;
33921 duk_json_enc_ctx js_ctx_alloc;
33922 duk_json_enc_ctx *js_ctx = &js_ctx_alloc;
33923 duk_hobject *h;
33924 duk_idx_t idx_holder;
33925 duk_idx_t entry_top;
33926
33927 /* negative top-relative indices not allowed now */
33928 DUK_ASSERT(idx_value == DUK_INVALID_INDEX || idx_value >= 0);
33929 DUK_ASSERT(idx_replacer == DUK_INVALID_INDEX || idx_replacer >= 0);
33930 DUK_ASSERT(idx_space == DUK_INVALID_INDEX || idx_space >= 0);
33931
33932 DUK_DDD(DUK_DDDPRINT("JSON stringify start: value=%!T, replacer=%!T, space=%!T, flags=0x%08lx, stack_top=%ld",
33933 (duk_tval *) duk_get_tval(ctx, idx_value),
33934 (duk_tval *) duk_get_tval(ctx, idx_replacer),
33935 (duk_tval *) duk_get_tval(ctx, idx_space),
33936 (unsigned long) flags,
33937 (long) duk_get_top(ctx)));
33938
33939 entry_top = duk_get_top(ctx);
33940
33941 /*
33942 * Context init
33943 */
33944
33945 DUK_MEMZERO(&js_ctx_alloc, sizeof(js_ctx_alloc));
33946 js_ctx->thr = thr;
33947#if defined(DUK_USE_EXPLICIT_NULL_INIT)
33948 js_ctx->h_replacer = NULL;
33949 js_ctx->h_gap = NULL;
33950#endif
33951 js_ctx->idx_proplist = -1;
33952
33953 /* Flag handling currently assumes that flags are consistent. This is OK
33954 * because the call sites are now strictly controlled.
33955 */
33956
33957 js_ctx->flags = flags;
33958 js_ctx->flag_ascii_only = flags & DUK_JSON_FLAG_ASCII_ONLY;
33959 js_ctx->flag_avoid_key_quotes = flags & DUK_JSON_FLAG_AVOID_KEY_QUOTES;
33960#if defined(DUK_USE_JX)
33961 js_ctx->flag_ext_custom = flags & DUK_JSON_FLAG_EXT_CUSTOM;
33962#endif
33963#if defined(DUK_USE_JC)
33964 js_ctx->flag_ext_compatible = flags & DUK_JSON_FLAG_EXT_COMPATIBLE;
33965#endif
33966#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
33967 js_ctx->flag_ext_custom_or_compatible = flags & (DUK_JSON_FLAG_EXT_CUSTOM | DUK_JSON_FLAG_EXT_COMPATIBLE);
33968#endif
33969
33970 /* The #if defined() clutter here handles the JX/JC enable/disable
33971 * combinations properly.
33972 */
33973#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
33974 js_ctx->stridx_custom_undefined = DUK_STRIDX_LC_NULL; /* standard JSON; array gaps */
33975#if defined(DUK_USE_JX)
33976 if (flags & DUK_JSON_FLAG_EXT_CUSTOM) {
33977 js_ctx->stridx_custom_undefined = DUK_STRIDX_LC_UNDEFINED;
33978 js_ctx->stridx_custom_nan = DUK_STRIDX_NAN;
33979 js_ctx->stridx_custom_neginf = DUK_STRIDX_MINUS_INFINITY;
33980 js_ctx->stridx_custom_posinf = DUK_STRIDX_INFINITY;
33981 js_ctx->stridx_custom_function =
33982 (flags & DUK_JSON_FLAG_AVOID_KEY_QUOTES) ?
33983 DUK_STRIDX_JSON_EXT_FUNCTION2 :
33984 DUK_STRIDX_JSON_EXT_FUNCTION1;
33985 }
33986#endif /* DUK_USE_JX */
33987#if defined(DUK_USE_JX) && defined(DUK_USE_JC)
33988 else
33989#endif /* DUK_USE_JX && DUK_USE_JC */
33990#if defined(DUK_USE_JC)
33991 if (js_ctx->flags & DUK_JSON_FLAG_EXT_COMPATIBLE) {
33992 js_ctx->stridx_custom_undefined = DUK_STRIDX_JSON_EXT_UNDEFINED;
33993 js_ctx->stridx_custom_nan = DUK_STRIDX_JSON_EXT_NAN;
33994 js_ctx->stridx_custom_neginf = DUK_STRIDX_JSON_EXT_NEGINF;
33995 js_ctx->stridx_custom_posinf = DUK_STRIDX_JSON_EXT_POSINF;
33996 js_ctx->stridx_custom_function = DUK_STRIDX_JSON_EXT_FUNCTION1;
33997 }
33998#endif /* DUK_USE_JC */
33999#endif /* DUK_USE_JX || DUK_USE_JC */
34000
34001#if defined(DUK_USE_JX) || defined(DUK_USE_JC)
34002 if (js_ctx->flags & (DUK_JSON_FLAG_EXT_CUSTOM |
34003 DUK_JSON_FLAG_EXT_COMPATIBLE)) {
34004 DUK_ASSERT(js_ctx->mask_for_undefined == 0); /* already zero */
34005 }
34006 else
34007#endif /* DUK_USE_JX || DUK_USE_JC */
34008 {
34009 /* Plain buffer is treated like ArrayBuffer and serialized.
34010 * Lightfuncs are treated like objects, but JSON explicitly
34011 * skips serializing Function objects so we can just reject
34012 * lightfuncs here.
34013 */
34014 js_ctx->mask_for_undefined = DUK_TYPE_MASK_UNDEFINED |
34015 DUK_TYPE_MASK_POINTER |
34016 DUK_TYPE_MASK_LIGHTFUNC;
34017 }
34018
34019 DUK_BW_INIT_PUSHBUF(thr, &js_ctx->bw, DUK__JSON_STRINGIFY_BUFSIZE);
34020
34021 js_ctx->idx_loop = duk_push_bare_object(ctx);
34022 DUK_ASSERT(js_ctx->idx_loop >= 0);
34023
34024 /* [ ... buf loop ] */
34025
34026 /*
34027 * Process replacer/proplist (2nd argument to JSON.stringify)
34028 */
34029
34030 h = duk_get_hobject(ctx, idx_replacer);
34031 if (h != NULL) {
34032 if (DUK_HOBJECT_IS_CALLABLE(h)) {
34033 js_ctx->h_replacer = h;
34034 } else if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_ARRAY) {
34035 /* Here the specification requires correct array index enumeration
34036 * which is a bit tricky for sparse arrays (it is handled by the
34037 * enum setup code). We now enumerate ancestors too, although the
34038 * specification is not very clear on whether that is required.
34039 */
34040
34041 duk_uarridx_t plist_idx = 0;
34042 duk_small_uint_t enum_flags;
34043
34044 js_ctx->idx_proplist = duk_push_array(ctx); /* XXX: array internal? */
34045
34046 enum_flags = DUK_ENUM_ARRAY_INDICES_ONLY |
34047 DUK_ENUM_SORT_ARRAY_INDICES; /* expensive flag */
34048 duk_enum(ctx, idx_replacer, enum_flags);
34049 while (duk_next(ctx, -1 /*enum_index*/, 1 /*get_value*/)) {
34050 /* [ ... proplist enum_obj key val ] */
34051 if (duk__enc_allow_into_proplist(duk_get_tval(ctx, -1))) {
34052 /* XXX: duplicates should be eliminated here */
34053 DUK_DDD(DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> accept",
34054 (duk_tval *) duk_get_tval(ctx, -2),
34055 (duk_tval *) duk_get_tval(ctx, -1)));
34056 duk_to_string(ctx, -1); /* extra coercion of strings is OK */
34057 duk_put_prop_index(ctx, -4, plist_idx); /* -> [ ... proplist enum_obj key ] */
34058 plist_idx++;
34059 duk_pop(ctx);
34060 } else {
34061 DUK_DDD(DUK_DDDPRINT("proplist enum: key=%!T, val=%!T --> reject",
34062 (duk_tval *) duk_get_tval(ctx, -2),
34063 (duk_tval *) duk_get_tval(ctx, -1)));
34064 duk_pop_2(ctx);
34065 }
34066 }
34067 duk_pop(ctx); /* pop enum */
34068
34069 /* [ ... proplist ] */
34070 }
34071 }
34072
34073 /* [ ... buf loop (proplist) ] */
34074
34075 /*
34076 * Process space (3rd argument to JSON.stringify)
34077 */
34078
34079 h = duk_get_hobject(ctx, idx_space);
34080 if (h != NULL) {
34081 int c = DUK_HOBJECT_GET_CLASS_NUMBER(h);
34082 if (c == DUK_HOBJECT_CLASS_NUMBER) {
34083 duk_to_number(ctx, idx_space);
34084 } else if (c == DUK_HOBJECT_CLASS_STRING) {
34085 duk_to_string(ctx, idx_space);
34086 }
34087 }
34088
34089 if (duk_is_number(ctx, idx_space)) {
34090 duk_small_int_t nspace;
34091 /* spaces[] must be static to allow initializer with old compilers like BCC */
34092 static const char spaces[10] = {
34093 DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE,
34094 DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE, DUK_ASC_SPACE,
34095 DUK_ASC_SPACE, DUK_ASC_SPACE
34096 }; /* XXX: helper */
34097
34098 /* ToInteger() coercion; NaN -> 0, infinities are clamped to 0 and 10 */
34099 nspace = (duk_small_int_t) duk_to_int_clamped(ctx, idx_space, 0 /*minval*/, 10 /*maxval*/);
34100 DUK_ASSERT(nspace >= 0 && nspace <= 10);
34101
34102 duk_push_lstring(ctx, spaces, (duk_size_t) nspace);
34103 js_ctx->h_gap = duk_known_hstring(ctx, -1);
34104 DUK_ASSERT(js_ctx->h_gap != NULL);
34105 } else if (duk_is_string_notsymbol(ctx, idx_space)) {
34106 duk_dup(ctx, idx_space);
34107 duk_substring(ctx, -1, 0, 10); /* clamp to 10 chars */
34108 js_ctx->h_gap = duk_known_hstring(ctx, -1);
34109 } else {
34110 /* nop */
34111 }
34112
34113 if (js_ctx->h_gap != NULL) {
34114 /* if gap is empty, behave as if not given at all */
34115 if (DUK_HSTRING_GET_CHARLEN(js_ctx->h_gap) == 0) {
34116 js_ctx->h_gap = NULL;
34117 }
34118 }
34119
34120 /* [ ... buf loop (proplist) (gap) ] */
34121
34122 /*
34123 * Fast path: assume no mutation, iterate object property tables
34124 * directly; bail out if that assumption doesn't hold.
34125 */
34126
34127#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
34128 if (js_ctx->h_replacer == NULL && /* replacer is a mutation risk */
34129 js_ctx->idx_proplist == -1) { /* proplist is very rare */
34130 duk_int_t pcall_rc;
34131 duk_small_uint_t prev_mark_and_sweep_base_flags;
34132
34133 DUK_DD(DUK_DDPRINT("try JSON.stringify() fast path"));
34134
34135 /* Use recursion_limit to ensure we don't overwrite js_ctx->visiting[]
34136 * array so we don't need two counter checks in the fast path. The
34137 * slow path has a much larger recursion limit which we'll use if
34138 * necessary.
34139 */
34140 DUK_ASSERT(DUK_USE_JSON_ENC_RECLIMIT >= DUK_JSON_ENC_LOOPARRAY);
34141 js_ctx->recursion_limit = DUK_JSON_ENC_LOOPARRAY;
34142 DUK_ASSERT(js_ctx->recursion_depth == 0);
34143
34144 /* Execute the fast path in a protected call. If any error is thrown,
34145 * fall back to the slow path. This includes e.g. recursion limit
34146 * because the fast path has a smaller recursion limit (and simpler,
34147 * limited loop detection).
34148 */
34149
34150 duk_dup(ctx, idx_value);
34151
34152 /* Must prevent finalizers which may have arbitrary side effects. */
34153 prev_mark_and_sweep_base_flags = thr->heap->mark_and_sweep_base_flags;
34154 thr->heap->mark_and_sweep_base_flags |=
34155 DUK_MS_FLAG_NO_FINALIZERS | /* avoid attempts to add/remove object keys */
34156 DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid attempt to compact any objects */
34157
34158 pcall_rc = duk_safe_call(ctx, duk__json_stringify_fast, (void *) js_ctx /*udata*/, 1 /*nargs*/, 0 /*nret*/);
34159
34160 thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
34161
34162 if (pcall_rc == DUK_EXEC_SUCCESS) {
34163 DUK_DD(DUK_DDPRINT("fast path successful"));
34164 DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw);
34165 goto replace_finished;
34166 }
34167
34168 /* We come here for actual aborts (like encountering .toJSON())
34169 * but also for recursion/loop errors. Bufwriter size can be
34170 * kept because we'll probably need at least as much as we've
34171 * allocated so far.
34172 */
34173 DUK_D(DUK_DPRINT("fast path failed, serialize using slow path instead"));
34174 DUK_BW_RESET_SIZE(thr, &js_ctx->bw);
34175 js_ctx->recursion_depth = 0;
34176 }
34177#endif
34178
34179 /*
34180 * Create wrapper object and serialize
34181 */
34182
34183 idx_holder = duk_push_object(ctx);
34184 duk_dup(ctx, idx_value);
34185 duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_EMPTY_STRING);
34186
34187 DUK_DDD(DUK_DDDPRINT("before: flags=0x%08lx, loop=%!T, replacer=%!O, "
34188 "proplist=%!T, gap=%!O, holder=%!T",
34189 (unsigned long) js_ctx->flags,
34190 (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop),
34191 (duk_heaphdr *) js_ctx->h_replacer,
34192 (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(ctx, js_ctx->idx_proplist) : NULL),
34193 (duk_heaphdr *) js_ctx->h_gap,
34194 (duk_tval *) duk_get_tval(ctx, -1)));
34195
34196 /* serialize the wrapper with empty string key */
34197
34198 duk_push_hstring_empty(ctx);
34199
34200 /* [ ... buf loop (proplist) (gap) holder "" ] */
34201
34202 js_ctx->recursion_limit = DUK_USE_JSON_ENC_RECLIMIT;
34203 DUK_ASSERT(js_ctx->recursion_depth == 0);
34204
34205 if (DUK_UNLIKELY(duk__enc_value(js_ctx, idx_holder) == 0)) { /* [ ... holder key ] -> [ ... holder ] */
34206 /* Result is undefined. */
34207 duk_push_undefined(ctx);
34208 } else {
34209 /* Convert buffer to result string. */
34210 DUK_BW_PUSH_AS_STRING(thr, &js_ctx->bw);
34211 }
34212
34213 DUK_DDD(DUK_DDDPRINT("after: flags=0x%08lx, loop=%!T, replacer=%!O, "
34214 "proplist=%!T, gap=%!O, holder=%!T",
34215 (unsigned long) js_ctx->flags,
34216 (duk_tval *) duk_get_tval(ctx, js_ctx->idx_loop),
34217 (duk_heaphdr *) js_ctx->h_replacer,
34218 (duk_tval *) (js_ctx->idx_proplist >= 0 ? duk_get_tval(ctx, js_ctx->idx_proplist) : NULL),
34219 (duk_heaphdr *) js_ctx->h_gap,
34220 (duk_tval *) duk_get_tval(ctx, idx_holder)));
34221
34222 /* The stack has a variable shape here, so force it to the
34223 * desired one explicitly.
34224 */
34225
34226#if defined(DUK_USE_JSON_STRINGIFY_FASTPATH)
34227 replace_finished:
34228#endif
34229 duk_replace(ctx, entry_top);
34230 duk_set_top(ctx, entry_top + 1);
34231
34232 DUK_DDD(DUK_DDDPRINT("JSON stringify end: value=%!T, replacer=%!T, space=%!T, "
34233 "flags=0x%08lx, result=%!T, stack_top=%ld",
34234 (duk_tval *) duk_get_tval(ctx, idx_value),
34235 (duk_tval *) duk_get_tval(ctx, idx_replacer),
34236 (duk_tval *) duk_get_tval(ctx, idx_space),
34237 (unsigned long) flags,
34238 (duk_tval *) duk_get_tval(ctx, -1),
34239 (long) duk_get_top(ctx)));
34240
34241 DUK_ASSERT(duk_get_top(ctx) == entry_top + 1);
34242}
34243
34244#if defined(DUK_USE_JSON_BUILTIN)
34245
34246/*
34247 * Entry points
34248 */
34249
34250DUK_INTERNAL duk_ret_t duk_bi_json_object_parse(duk_context *ctx) {
34251 duk_bi_json_parse_helper(ctx,
34252 0 /*idx_value*/,
34253 1 /*idx_replacer*/,
34254 0 /*flags*/);
34255 return 1;
34256}
34257
34258DUK_INTERNAL duk_ret_t duk_bi_json_object_stringify(duk_context *ctx) {
34259 duk_bi_json_stringify_helper(ctx,
34260 0 /*idx_value*/,
34261 1 /*idx_replacer*/,
34262 2 /*idx_space*/,
34263 0 /*flags*/);
34264 return 1;
34265}
34266
34267#endif /* DUK_USE_JSON_BUILTIN */
34268
34269#endif /* DUK_USE_JSON_SUPPORT */
34270
34271/* automatic undefs */
34272#undef DUK__EMIT_1
34273#undef DUK__EMIT_2
34274#undef DUK__EMIT_CSTR
34275#undef DUK__EMIT_HSTR
34276#undef DUK__EMIT_STRIDX
34277#undef DUK__JSON_DECSTR_BUFSIZE
34278#undef DUK__JSON_DECSTR_CHUNKSIZE
34279#undef DUK__JSON_ENCSTR_CHUNKSIZE
34280#undef DUK__JSON_MAX_ESC_LEN
34281#undef DUK__JSON_STRINGIFY_BUFSIZE
34282#undef DUK__MKESC
34283#undef DUK__UNEMIT_1
34284/*
34285 * Math built-ins
34286 */
34287
34288/* #include duk_internal.h -> already included */
34289
34290#if defined(DUK_USE_MATH_BUILTIN)
34291
34292/*
34293 * Use static helpers which can work with math.h functions matching
34294 * the following signatures. This is not portable if any of these math
34295 * functions is actually a macro.
34296 *
34297 * Typing here is intentionally 'double' wherever values interact with
34298 * the standard library APIs.
34299 */
34300
34301typedef double (*duk__one_arg_func)(double);
34302typedef double (*duk__two_arg_func)(double, double);
34303
34304DUK_LOCAL duk_ret_t duk__math_minmax(duk_context *ctx, duk_double_t initial, duk__two_arg_func min_max) {
34305 duk_idx_t n = duk_get_top(ctx);
34306 duk_idx_t i;
34307 duk_double_t res = initial;
34308 duk_double_t t;
34309
34310 /*
34311 * Note: fmax() does not match the E5 semantics. E5 requires
34312 * that if -any- input to Math.max() is a NaN, the result is a
34313 * NaN. fmax() will return a NaN only if -both- inputs are NaN.
34314 * Same applies to fmin().
34315 *
34316 * Note: every input value must be coerced with ToNumber(), even
34317 * if we know the result will be a NaN anyway: ToNumber() may have
34318 * side effects for which even order of evaluation matters.
34319 */
34320
34321 for (i = 0; i < n; i++) {
34322 t = duk_to_number(ctx, i);
34323 if (DUK_FPCLASSIFY(t) == DUK_FP_NAN || DUK_FPCLASSIFY(res) == DUK_FP_NAN) {
34324 /* Note: not normalized, but duk_push_number() will normalize */
34325 res = (duk_double_t) DUK_DOUBLE_NAN;
34326 } else {
34327 res = (duk_double_t) min_max(res, (double) t);
34328 }
34329 }
34330
34331 duk_push_number(ctx, res);
34332 return 1;
34333}
34334
34335DUK_LOCAL double duk__fmin_fixed(double x, double y) {
34336 /* fmin() with args -0 and +0 is not guaranteed to return
34337 * -0 as Ecmascript requires.
34338 */
34339 if (x == 0 && y == 0) {
34340 duk_double_union du1, du2;
34341 du1.d = x;
34342 du2.d = y;
34343
34344 /* Already checked to be zero so these must hold, and allow us
34345 * to check for "x is -0 or y is -0" by ORing the high parts
34346 * for comparison.
34347 */
34348 DUK_ASSERT(du1.ui[DUK_DBL_IDX_UI0] == 0 || du1.ui[DUK_DBL_IDX_UI0] == 0x80000000UL);
34349 DUK_ASSERT(du2.ui[DUK_DBL_IDX_UI0] == 0 || du2.ui[DUK_DBL_IDX_UI0] == 0x80000000UL);
34350
34351 /* XXX: what's the safest way of creating a negative zero? */
34352 if ((du1.ui[DUK_DBL_IDX_UI0] | du2.ui[DUK_DBL_IDX_UI0]) != 0) {
34353 /* Enter here if either x or y (or both) is -0. */
34354 return -0.0;
34355 } else {
34356 return +0.0;
34357 }
34358 }
34359 return duk_double_fmin(x, y);
34360}
34361
34362DUK_LOCAL double duk__fmax_fixed(double x, double y) {
34363 /* fmax() with args -0 and +0 is not guaranteed to return
34364 * +0 as Ecmascript requires.
34365 */
34366 if (x == 0 && y == 0) {
34367 if (DUK_SIGNBIT(x) == 0 || DUK_SIGNBIT(y) == 0) {
34368 return +0.0;
34369 } else {
34370 return -0.0;
34371 }
34372 }
34373 return duk_double_fmax(x, y);
34374}
34375
34376#if defined(DUK_USE_ES6)
34377DUK_LOCAL double duk__cbrt(double x) {
34378 /* cbrt() is C99. To avoid hassling embedders with the need to provide a
34379 * cube root function, we can get by with pow(). The result is not
34380 * identical, but that's OK: ES2015 says it's implementation-dependent.
34381 */
34382
34383#if defined(DUK_CBRT)
34384 /* cbrt() matches ES2015 requirements. */
34385 return DUK_CBRT(x);
34386#else
34387 duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x);
34388
34389 /* pow() does not, however. */
34390 if (c == DUK_FP_NAN || c == DUK_FP_INFINITE || c == DUK_FP_ZERO) {
34391 return x;
34392 }
34393 if (DUK_SIGNBIT(x)) {
34394 return -DUK_POW(-x, 1.0 / 3.0);
34395 } else {
34396 return DUK_POW(x, 1.0 / 3.0);
34397 }
34398#endif
34399}
34400
34401DUK_LOCAL double duk__log2(double x) {
34402#if defined(DUK_LOG2)
34403 return DUK_LOG2(x);
34404#else
34405 return DUK_LOG(x) * DUK_DOUBLE_LOG2E;
34406#endif
34407}
34408
34409DUK_LOCAL double duk__log10(double x) {
34410#if defined(DUK_LOG10)
34411 return DUK_LOG10(x);
34412#else
34413 return DUK_LOG(x) * DUK_DOUBLE_LOG10E;
34414#endif
34415}
34416
34417DUK_LOCAL double duk__trunc(double x) {
34418#if defined(DUK_TRUNC)
34419 return DUK_TRUNC(x);
34420#else
34421 /* Handles -0 correctly: -0.0 matches 'x >= 0.0' but floor()
34422 * is required to return -0 when the argument is -0.
34423 */
34424 return x >= 0.0 ? DUK_FLOOR(x) : DUK_CEIL(x);
34425#endif
34426}
34427#endif /* DUK_USE_ES6 */
34428
34429DUK_LOCAL double duk__round_fixed(double x) {
34430 /* Numbers half-way between integers must be rounded towards +Infinity,
34431 * e.g. -3.5 must be rounded to -3 (not -4). When rounded to zero, zero
34432 * sign must be set appropriately. E5.1 Section 15.8.2.15.
34433 *
34434 * Note that ANSI C round() is "round to nearest integer, away from zero",
34435 * which is incorrect for negative values. Here we make do with floor().
34436 */
34437
34438 duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x);
34439 if (c == DUK_FP_NAN || c == DUK_FP_INFINITE || c == DUK_FP_ZERO) {
34440 return x;
34441 }
34442
34443 /*
34444 * x is finite and non-zero
34445 *
34446 * -1.6 -> floor(-1.1) -> -2
34447 * -1.5 -> floor(-1.0) -> -1 (towards +Inf)
34448 * -1.4 -> floor(-0.9) -> -1
34449 * -0.5 -> -0.0 (special case)
34450 * -0.1 -> -0.0 (special case)
34451 * +0.1 -> +0.0 (special case)
34452 * +0.5 -> floor(+1.0) -> 1 (towards +Inf)
34453 * +1.4 -> floor(+1.9) -> 1
34454 * +1.5 -> floor(+2.0) -> 2 (towards +Inf)
34455 * +1.6 -> floor(+2.1) -> 2
34456 */
34457
34458 if (x >= -0.5 && x < 0.5) {
34459 /* +0.5 is handled by floor, this is on purpose */
34460 if (x < 0.0) {
34461 return -0.0;
34462 } else {
34463 return +0.0;
34464 }
34465 }
34466
34467 return DUK_FLOOR(x + 0.5);
34468}
34469
34470/* Wrappers for calling standard math library methods. These may be required
34471 * on platforms where one or more of the math built-ins are defined as macros
34472 * or inline functions and are thus not suitable to be used as function pointers.
34473 */
34474#if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS)
34475DUK_LOCAL double duk__fabs(double x) {
34476 return DUK_FABS(x);
34477}
34478DUK_LOCAL double duk__acos(double x) {
34479 return DUK_ACOS(x);
34480}
34481DUK_LOCAL double duk__asin(double x) {
34482 return DUK_ASIN(x);
34483}
34484DUK_LOCAL double duk__atan(double x) {
34485 return DUK_ATAN(x);
34486}
34487DUK_LOCAL double duk__ceil(double x) {
34488 return DUK_CEIL(x);
34489}
34490DUK_LOCAL double duk__cos(double x) {
34491 return DUK_COS(x);
34492}
34493DUK_LOCAL double duk__exp(double x) {
34494 return DUK_EXP(x);
34495}
34496DUK_LOCAL double duk__floor(double x) {
34497 return DUK_FLOOR(x);
34498}
34499DUK_LOCAL double duk__log(double x) {
34500 return DUK_LOG(x);
34501}
34502DUK_LOCAL double duk__sin(double x) {
34503 return DUK_SIN(x);
34504}
34505DUK_LOCAL double duk__sqrt(double x) {
34506 return DUK_SQRT(x);
34507}
34508DUK_LOCAL double duk__tan(double x) {
34509 return DUK_TAN(x);
34510}
34511DUK_LOCAL double duk__atan2_fixed(double x, double y) {
34512#if defined(DUK_USE_ATAN2_WORKAROUNDS)
34513 /* Specific fixes to common atan2() implementation issues:
34514 * - test-bug-mingw-math-issues.js
34515 */
34516 if (DUK_ISINF(x) && DUK_ISINF(y)) {
34517 if (DUK_SIGNBIT(x)) {
34518 if (DUK_SIGNBIT(y)) {
34519 return -2.356194490192345;
34520 } else {
34521 return -0.7853981633974483;
34522 }
34523 } else {
34524 if (DUK_SIGNBIT(y)) {
34525 return 2.356194490192345;
34526 } else {
34527 return 0.7853981633974483;
34528 }
34529 }
34530 }
34531#else
34532 /* Some ISO C assumptions. */
34533 DUK_ASSERT(DUK_ATAN2(DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY) == 0.7853981633974483);
34534 DUK_ASSERT(DUK_ATAN2(-DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY) == -0.7853981633974483);
34535 DUK_ASSERT(DUK_ATAN2(DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY) == 2.356194490192345);
34536 DUK_ASSERT(DUK_ATAN2(-DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY) == -2.356194490192345);
34537#endif
34538
34539 return DUK_ATAN2(x, y);
34540}
34541#endif /* DUK_USE_AVOID_PLATFORM_FUNCPTRS */
34542
34543/* order must match constants in genbuiltins.py */
34544DUK_LOCAL const duk__one_arg_func duk__one_arg_funcs[] = {
34545#if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS)
34546 duk__fabs,
34547 duk__acos,
34548 duk__asin,
34549 duk__atan,
34550 duk__ceil,
34551 duk__cos,
34552 duk__exp,
34553 duk__floor,
34554 duk__log,
34555 duk__round_fixed,
34556 duk__sin,
34557 duk__sqrt,
34558 duk__tan,
34559#if defined(DUK_USE_ES6)
34560 duk__cbrt,
34561 duk__log2,
34562 duk__log10,
34563 duk__trunc
34564#endif
34565#else /* DUK_USE_AVOID_PLATFORM_FUNCPTRS */
34566 DUK_FABS,
34567 DUK_ACOS,
34568 DUK_ASIN,
34569 DUK_ATAN,
34570 DUK_CEIL,
34571 DUK_COS,
34572 DUK_EXP,
34573 DUK_FLOOR,
34574 DUK_LOG,
34575 duk__round_fixed,
34576 DUK_SIN,
34577 DUK_SQRT,
34578 DUK_TAN,
34579#if defined(DUK_USE_ES6)
34580 duk__cbrt,
34581 duk__log2,
34582 duk__log10,
34583 duk__trunc
34584#endif
34585#endif /* DUK_USE_AVOID_PLATFORM_FUNCPTRS */
34586};
34587
34588/* order must match constants in genbuiltins.py */
34589DUK_LOCAL const duk__two_arg_func duk__two_arg_funcs[] = {
34590#if defined(DUK_USE_AVOID_PLATFORM_FUNCPTRS)
34591 duk__atan2_fixed,
34592 duk_js_arith_pow
34593#else
34594 duk__atan2_fixed,
34595 duk_js_arith_pow
34596#endif
34597};
34598
34599DUK_INTERNAL duk_ret_t duk_bi_math_object_onearg_shared(duk_context *ctx) {
34600 duk_small_int_t fun_idx = duk_get_current_magic(ctx);
34601 duk__one_arg_func fun;
34602 duk_double_t arg1;
34603
34604 DUK_ASSERT(fun_idx >= 0);
34605 DUK_ASSERT(fun_idx < (duk_small_int_t) (sizeof(duk__one_arg_funcs) / sizeof(duk__one_arg_func)));
34606 arg1 = duk_to_number(ctx, 0);
34607 fun = duk__one_arg_funcs[fun_idx];
34608 duk_push_number(ctx, (duk_double_t) fun((double) arg1));
34609 return 1;
34610}
34611
34612DUK_INTERNAL duk_ret_t duk_bi_math_object_twoarg_shared(duk_context *ctx) {
34613 duk_small_int_t fun_idx = duk_get_current_magic(ctx);
34614 duk__two_arg_func fun;
34615 duk_double_t arg1;
34616 duk_double_t arg2;
34617
34618 DUK_ASSERT(fun_idx >= 0);
34619 DUK_ASSERT(fun_idx < (duk_small_int_t) (sizeof(duk__two_arg_funcs) / sizeof(duk__two_arg_func)));
34620 arg1 = duk_to_number(ctx, 0); /* explicit ordered evaluation to match coercion semantics */
34621 arg2 = duk_to_number(ctx, 1);
34622 fun = duk__two_arg_funcs[fun_idx];
34623 duk_push_number(ctx, (duk_double_t) fun((double) arg1, (double) arg2));
34624 return 1;
34625}
34626
34627DUK_INTERNAL duk_ret_t duk_bi_math_object_max(duk_context *ctx) {
34628 return duk__math_minmax(ctx, -DUK_DOUBLE_INFINITY, duk__fmax_fixed);
34629}
34630
34631DUK_INTERNAL duk_ret_t duk_bi_math_object_min(duk_context *ctx) {
34632 return duk__math_minmax(ctx, DUK_DOUBLE_INFINITY, duk__fmin_fixed);
34633}
34634
34635DUK_INTERNAL duk_ret_t duk_bi_math_object_random(duk_context *ctx) {
34636 duk_push_number(ctx, (duk_double_t) DUK_UTIL_GET_RANDOM_DOUBLE((duk_hthread *) ctx));
34637 return 1;
34638}
34639
34640#if defined(DUK_USE_ES6)
34641DUK_INTERNAL duk_ret_t duk_bi_math_object_hypot(duk_context *ctx) {
34642 /*
34643 * E6 Section 20.2.2.18: Math.hypot
34644 *
34645 * - If no arguments are passed, the result is +0.
34646 * - If any argument is +inf, the result is +inf.
34647 * - If any argument is -inf, the result is +inf.
34648 * - If no argument is +inf or -inf, and any argument is NaN, the result is
34649 * NaN.
34650 * - If all arguments are either +0 or -0, the result is +0.
34651 */
34652
34653 duk_idx_t nargs;
34654 duk_idx_t i;
34655 duk_bool_t found_nan;
34656 duk_double_t max;
34657 duk_double_t sum, summand;
34658 duk_double_t comp, prelim;
34659 duk_double_t t;
34660
34661 nargs = duk_get_top(ctx);
34662
34663 /* Find the highest value. Also ToNumber() coerces. */
34664 max = 0.0;
34665 found_nan = 0;
34666 for (i = 0; i < nargs; i++) {
34667 t = DUK_FABS(duk_to_number(ctx, i));
34668 if (DUK_FPCLASSIFY(t) == DUK_FP_NAN) {
34669 found_nan = 1;
34670 } else {
34671 max = duk_double_fmax(max, t);
34672 }
34673 }
34674
34675 /* Early return cases. */
34676 if (max == DUK_DOUBLE_INFINITY) {
34677 duk_push_number(ctx, DUK_DOUBLE_INFINITY);
34678 return 1;
34679 } else if (found_nan) {
34680 duk_push_number(ctx, DUK_DOUBLE_NAN);
34681 return 1;
34682 } else if (max == 0.0) {
34683 duk_push_number(ctx, 0.0);
34684 /* Otherwise we'd divide by zero. */
34685 return 1;
34686 }
34687
34688 /* Use Kahan summation and normalize to the highest value to minimize
34689 * floating point rounding error and avoid overflow.
34690 *
34691 * https://en.wikipedia.org/wiki/Kahan_summation_algorithm
34692 */
34693 sum = 0.0;
34694 comp = 0.0;
34695 for (i = 0; i < nargs; i++) {
34696 t = DUK_FABS(duk_get_number(ctx, i)) / max;
34697 summand = (t * t) - comp;
34698 prelim = sum + summand;
34699 comp = (prelim - sum) - summand;
34700 sum = prelim;
34701 }
34702
34703 duk_push_number(ctx, (duk_double_t) DUK_SQRT(sum) * max);
34704 return 1;
34705}
34706#endif /* DUK_USE_ES6 */
34707
34708#endif /* DUK_USE_MATH_BUILTIN */
34709/*
34710 * Number built-ins
34711 */
34712
34713/* #include duk_internal.h -> already included */
34714
34715#if defined(DUK_USE_NUMBER_BUILTIN)
34716
34717DUK_LOCAL duk_double_t duk__push_this_number_plain(duk_context *ctx) {
34718 duk_hobject *h;
34719
34720 /* Number built-in accepts a plain number or a Number object (whose
34721 * internal value is operated on). Other types cause TypeError.
34722 */
34723
34724 duk_push_this(ctx);
34725 if (duk_is_number(ctx, -1)) {
34726 DUK_DDD(DUK_DDDPRINT("plain number value: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
34727 goto done;
34728 }
34729 h = duk_get_hobject(ctx, -1);
34730 if (!h ||
34731 (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_NUMBER)) {
34732 DUK_DDD(DUK_DDDPRINT("unacceptable this value: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
34733 DUK_ERROR_TYPE((duk_hthread *) ctx, "number expected");
34734 }
34735 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_VALUE);
34736 DUK_ASSERT(duk_is_number(ctx, -1));
34737 DUK_DDD(DUK_DDDPRINT("number object: %!T, internal value: %!T",
34738 (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1)));
34739 duk_remove_m2(ctx);
34740
34741 done:
34742 return duk_get_number(ctx, -1);
34743}
34744
34745DUK_INTERNAL duk_ret_t duk_bi_number_constructor(duk_context *ctx) {
34746 duk_hthread *thr = (duk_hthread *) ctx;
34747 duk_idx_t nargs;
34748 duk_hobject *h_this;
34749
34750 DUK_UNREF(thr);
34751
34752 /*
34753 * The Number constructor uses ToNumber(arg) for number coercion
34754 * (coercing an undefined argument to NaN). However, if the
34755 * argument is not given at all, +0 must be used instead. To do
34756 * this, a vararg function is used.
34757 */
34758
34759 nargs = duk_get_top(ctx);
34760 if (nargs == 0) {
34761 duk_push_int(ctx, 0);
34762 }
34763 duk_to_number(ctx, 0);
34764 duk_set_top(ctx, 1);
34765 DUK_ASSERT_TOP(ctx, 1);
34766
34767 if (!duk_is_constructor_call(ctx)) {
34768 return 1;
34769 }
34770
34771 /*
34772 * E5 Section 15.7.2.1 requires that the constructed object
34773 * must have the original Number.prototype as its internal
34774 * prototype. However, since Number.prototype is non-writable
34775 * and non-configurable, this doesn't have to be enforced here:
34776 * The default object (bound to 'this') is OK, though we have
34777 * to change its class.
34778 *
34779 * Internal value set to ToNumber(arg) or +0; if no arg given,
34780 * ToNumber(undefined) = NaN, so special treatment is needed
34781 * (above). String internal value is immutable.
34782 */
34783
34784 /* XXX: helper */
34785 duk_push_this(ctx);
34786 h_this = duk_known_hobject(ctx, -1);
34787 DUK_HOBJECT_SET_CLASS_NUMBER(h_this, DUK_HOBJECT_CLASS_NUMBER);
34788
34789 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_this) == thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE]);
34790 DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_this) == DUK_HOBJECT_CLASS_NUMBER);
34791 DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h_this));
34792
34793 duk_dup_0(ctx); /* -> [ val obj val ] */
34794 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
34795 return 0; /* no return value -> don't replace created value */
34796}
34797
34798DUK_INTERNAL duk_ret_t duk_bi_number_prototype_value_of(duk_context *ctx) {
34799 (void) duk__push_this_number_plain(ctx);
34800 return 1;
34801}
34802
34803DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_string(duk_context *ctx) {
34804 duk_small_int_t radix;
34805 duk_small_uint_t n2s_flags;
34806
34807 (void) duk__push_this_number_plain(ctx);
34808 if (duk_is_undefined(ctx, 0)) {
34809 radix = 10;
34810 } else {
34811 radix = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 2, 36);
34812 }
34813 DUK_DDD(DUK_DDDPRINT("radix=%ld", (long) radix));
34814
34815 n2s_flags = 0;
34816
34817 duk_numconv_stringify(ctx,
34818 radix /*radix*/,
34819 0 /*digits*/,
34820 n2s_flags /*flags*/);
34821 return 1;
34822}
34823
34824DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_locale_string(duk_context *ctx) {
34825 /* XXX: just use toString() for now; permitted although not recommended.
34826 * nargs==1, so radix is passed to toString().
34827 */
34828 return duk_bi_number_prototype_to_string(ctx);
34829}
34830
34831/*
34832 * toFixed(), toExponential(), toPrecision()
34833 */
34834
34835/* XXX: shared helper for toFixed(), toExponential(), toPrecision()? */
34836
34837DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_fixed(duk_context *ctx) {
34838 duk_small_int_t frac_digits;
34839 duk_double_t d;
34840 duk_small_int_t c;
34841 duk_small_uint_t n2s_flags;
34842
34843 frac_digits = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 0, 20);
34844 d = duk__push_this_number_plain(ctx);
34845
34846 c = (duk_small_int_t) DUK_FPCLASSIFY(d);
34847 if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
34848 goto use_to_string;
34849 }
34850
34851 if (d >= 1.0e21 || d <= -1.0e21) {
34852 goto use_to_string;
34853 }
34854
34855 n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT |
34856 DUK_N2S_FLAG_FRACTION_DIGITS;
34857
34858 duk_numconv_stringify(ctx,
34859 10 /*radix*/,
34860 frac_digits /*digits*/,
34861 n2s_flags /*flags*/);
34862 return 1;
34863
34864 use_to_string:
34865 DUK_ASSERT_TOP(ctx, 2);
34866 duk_to_string(ctx, -1);
34867 return 1;
34868}
34869
34870DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_exponential(duk_context *ctx) {
34871 duk_bool_t frac_undefined;
34872 duk_small_int_t frac_digits;
34873 duk_double_t d;
34874 duk_small_int_t c;
34875 duk_small_uint_t n2s_flags;
34876
34877 d = duk__push_this_number_plain(ctx);
34878
34879 frac_undefined = duk_is_undefined(ctx, 0);
34880 duk_to_int(ctx, 0); /* for side effects */
34881
34882 c = (duk_small_int_t) DUK_FPCLASSIFY(d);
34883 if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
34884 goto use_to_string;
34885 }
34886
34887 frac_digits = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 0, 20);
34888
34889 n2s_flags = DUK_N2S_FLAG_FORCE_EXP |
34890 (frac_undefined ? 0 : DUK_N2S_FLAG_FIXED_FORMAT);
34891
34892 duk_numconv_stringify(ctx,
34893 10 /*radix*/,
34894 frac_digits + 1 /*leading digit + fractions*/,
34895 n2s_flags /*flags*/);
34896 return 1;
34897
34898 use_to_string:
34899 DUK_ASSERT_TOP(ctx, 2);
34900 duk_to_string(ctx, -1);
34901 return 1;
34902}
34903
34904DUK_INTERNAL duk_ret_t duk_bi_number_prototype_to_precision(duk_context *ctx) {
34905 /* The specification has quite awkward order of coercion and
34906 * checks for toPrecision(). The operations below are a bit
34907 * reordered, within constraints of observable side effects.
34908 */
34909
34910 duk_double_t d;
34911 duk_small_int_t prec;
34912 duk_small_int_t c;
34913 duk_small_uint_t n2s_flags;
34914
34915 DUK_ASSERT_TOP(ctx, 1);
34916
34917 d = duk__push_this_number_plain(ctx);
34918 if (duk_is_undefined(ctx, 0)) {
34919 goto use_to_string;
34920 }
34921 DUK_ASSERT_TOP(ctx, 2);
34922
34923 duk_to_int(ctx, 0); /* for side effects */
34924
34925 c = (duk_small_int_t) DUK_FPCLASSIFY(d);
34926 if (c == DUK_FP_NAN || c == DUK_FP_INFINITE) {
34927 goto use_to_string;
34928 }
34929
34930 prec = (duk_small_int_t) duk_to_int_check_range(ctx, 0, 1, 21);
34931
34932 n2s_flags = DUK_N2S_FLAG_FIXED_FORMAT |
34933 DUK_N2S_FLAG_NO_ZERO_PAD;
34934
34935 duk_numconv_stringify(ctx,
34936 10 /*radix*/,
34937 prec /*digits*/,
34938 n2s_flags /*flags*/);
34939 return 1;
34940
34941 use_to_string:
34942 /* Used when precision is undefined; also used for NaN (-> "NaN"),
34943 * and +/- infinity (-> "Infinity", "-Infinity").
34944 */
34945
34946 DUK_ASSERT_TOP(ctx, 2);
34947 duk_to_string(ctx, -1);
34948 return 1;
34949}
34950
34951#endif /* DUK_USE_NUMBER_BUILTIN */
34952/*
34953 * Object built-ins
34954 */
34955
34956/* #include duk_internal.h -> already included */
34957
34958/* Needed even when Object built-in disabled. */
34959DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_string(duk_context *ctx) {
34960 duk_tval *tv;
34961 tv = DUK_HTHREAD_THIS_PTR((duk_hthread *) ctx);
34962 /* XXX: This is not entirely correct anymore; in ES2015 the
34963 * default lookup should use @@toStringTag to come up with
34964 * e.g. [object Symbol].
34965 */
34966 duk_push_class_string_tval(ctx, tv);
34967 return 1;
34968}
34969
34970#if defined(DUK_USE_OBJECT_BUILTIN)
34971DUK_INTERNAL duk_ret_t duk_bi_object_constructor(duk_context *ctx) {
34972 duk_uint_t arg_mask;
34973
34974 arg_mask = duk_get_type_mask(ctx, 0);
34975
34976 if (!duk_is_constructor_call(ctx) && /* not a constructor call */
34977 ((arg_mask & (DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_UNDEFINED)) == 0)) { /* and argument not null or undefined */
34978 duk_to_object(ctx, 0);
34979 return 1;
34980 }
34981
34982 /* Pointer and buffer primitive values are treated like other
34983 * primitives values which have a fully fledged object counterpart:
34984 * promote to an object value. Lightfuncs and plain buffers are
34985 * coerced with ToObject() even they could also be returned as is.
34986 */
34987 if (arg_mask & (DUK_TYPE_MASK_OBJECT |
34988 DUK_TYPE_MASK_STRING |
34989 DUK_TYPE_MASK_BOOLEAN |
34990 DUK_TYPE_MASK_NUMBER |
34991 DUK_TYPE_MASK_POINTER |
34992 DUK_TYPE_MASK_BUFFER |
34993 DUK_TYPE_MASK_LIGHTFUNC)) {
34994 /* For DUK_TYPE_OBJECT the coercion is a no-op and could
34995 * be checked for explicitly, but Object(obj) calls are
34996 * not very common so opt for minimal footprint.
34997 */
34998 duk_to_object(ctx, 0);
34999 return 1;
35000 }
35001
35002 (void) duk_push_object_helper(ctx,
35003 DUK_HOBJECT_FLAG_EXTENSIBLE |
35004 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
35005 DUK_BIDX_OBJECT_PROTOTYPE);
35006 return 1;
35007}
35008#endif /* DUK_USE_OBJECT_BUILTIN */
35009
35010#if defined(DUK_USE_OBJECT_BUILTIN) && defined(DUK_USE_ES6)
35011DUK_INTERNAL duk_ret_t duk_bi_object_constructor_assign(duk_context *ctx) {
35012 duk_idx_t nargs;
35013 duk_int_t idx;
35014
35015 nargs = duk_get_top_require_min(ctx, 1 /*min_top*/);
35016
35017 duk_to_object(ctx, 0);
35018 for (idx = 1; idx < nargs; idx++) {
35019 /* E7 19.1.2.1 (step 4a) */
35020 if (duk_is_null_or_undefined(ctx, idx)) {
35021 continue;
35022 }
35023
35024 /* duk_enum() respects ES2015+ [[OwnPropertyKeys]] ordering, which is
35025 * convenient here.
35026 */
35027 duk_to_object(ctx, idx);
35028 duk_enum(ctx, idx, DUK_ENUM_OWN_PROPERTIES_ONLY);
35029 while (duk_next(ctx, -1, 1 /*get_value*/)) {
35030 /* [ target ... enum key value ] */
35031 duk_put_prop(ctx, 0);
35032 /* [ target ... enum ] */
35033 }
35034 /* Could pop enumerator, but unnecessary because of duk_set_top()
35035 * below.
35036 */
35037 }
35038
35039 duk_set_top(ctx, 1);
35040 return 1;
35041}
35042#endif
35043
35044#if defined(DUK_USE_OBJECT_BUILTIN) && defined(DUK_USE_ES6)
35045DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is(duk_context *ctx) {
35046 DUK_ASSERT_TOP(ctx, 2);
35047 duk_push_boolean(ctx, duk_samevalue(ctx, 0, 1));
35048 return 1;
35049}
35050#endif
35051
35052#if defined(DUK_USE_OBJECT_BUILTIN)
35053DUK_INTERNAL duk_ret_t duk_bi_object_constructor_create(duk_context *ctx) {
35054 duk_hobject *proto;
35055
35056 DUK_ASSERT_TOP(ctx, 2);
35057
35058#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
35059 duk_hbufobj_promote_plain(ctx, 0);
35060#endif
35061 proto = duk_require_hobject_accept_mask(ctx, 0, DUK_TYPE_MASK_NULL);
35062 DUK_ASSERT(proto != NULL || duk_is_null(ctx, 0));
35063
35064 (void) duk_push_object_helper_proto(ctx,
35065 DUK_HOBJECT_FLAG_EXTENSIBLE |
35066 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
35067 proto);
35068
35069 if (!duk_is_undefined(ctx, 1)) {
35070 /* [ O Properties obj ] */
35071
35072 duk_replace(ctx, 0);
35073
35074 /* [ obj Properties ] */
35075
35076 /* Just call the "original" Object.defineProperties() to
35077 * finish up.
35078 */
35079
35080 return duk_bi_object_constructor_define_properties(ctx);
35081 }
35082
35083 /* [ O Properties obj ] */
35084
35085 return 1;
35086}
35087#endif /* DUK_USE_OBJECT_BUILTIN */
35088
35089#if defined(DUK_USE_OBJECT_BUILTIN)
35090DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_properties(duk_context *ctx) {
35091 duk_small_uint_t pass;
35092 duk_uint_t defprop_flags;
35093 duk_hobject *obj;
35094 duk_idx_t idx_value;
35095 duk_hobject *get;
35096 duk_hobject *set;
35097
35098 /* Lightfunc and plain buffer handling by ToObject() coercion. */
35099 obj = duk_require_hobject_promote_mask(ctx, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
35100 DUK_ASSERT(obj != NULL);
35101
35102 duk_to_object(ctx, 1); /* properties object */
35103
35104 DUK_DDD(DUK_DDDPRINT("target=%!iT, properties=%!iT",
35105 (duk_tval *) duk_get_tval(ctx, 0),
35106 (duk_tval *) duk_get_tval(ctx, 1)));
35107
35108 /*
35109 * Two pass approach to processing the property descriptors.
35110 * On first pass validate and normalize all descriptors before
35111 * any changes are made to the target object. On second pass
35112 * make the actual modifications to the target object.
35113 *
35114 * Right now we'll just use the same normalize/validate helper
35115 * on both passes, ignoring its outputs on the first pass.
35116 */
35117
35118 for (pass = 0; pass < 2; pass++) {
35119 duk_set_top(ctx, 2); /* -> [ hobject props ] */
35120 duk_enum(ctx, 1, DUK_ENUM_OWN_PROPERTIES_ONLY | DUK_ENUM_INCLUDE_SYMBOLS /*enum_flags*/);
35121
35122 for (;;) {
35124
35125 /* [ hobject props enum(props) ] */
35126
35127 duk_set_top(ctx, 3);
35128
35129 if (!duk_next(ctx, 2, 1 /*get_value*/)) {
35130 break;
35131 }
35132
35133 DUK_DDD(DUK_DDDPRINT("-> key=%!iT, desc=%!iT",
35134 (duk_tval *) duk_get_tval(ctx, -2),
35135 (duk_tval *) duk_get_tval(ctx, -1)));
35136
35137 /* [ hobject props enum(props) key desc ] */
35138
35139 duk_hobject_prepare_property_descriptor(ctx,
35140 4 /*idx_desc*/,
35141 &defprop_flags,
35142 &idx_value,
35143 &get,
35144 &set);
35145
35146 /* [ hobject props enum(props) key desc [multiple values] ] */
35147
35148 if (pass == 0) {
35149 continue;
35150 }
35151
35152 /* This allows symbols on purpose. */
35153 key = duk_known_hstring(ctx, 3);
35154 DUK_ASSERT(key != NULL);
35155
35156 duk_hobject_define_property_helper(ctx,
35157 defprop_flags,
35158 obj,
35159 key,
35160 idx_value,
35161 get,
35162 set,
35163 1 /*throw_flag*/);
35164 }
35165 }
35166
35167 /*
35168 * Return target object
35169 */
35170
35171 duk_dup_0(ctx);
35172 return 1;
35173}
35174#endif /* DUK_USE_OBJECT_BUILTIN */
35175
35176#if defined(DUK_USE_OBJECT_BUILTIN)
35177DUK_INTERNAL duk_ret_t duk_bi_object_constructor_seal_freeze_shared(duk_context *ctx) {
35178 duk_hthread *thr = (duk_hthread *) ctx;
35179 duk_hobject *h;
35180 duk_bool_t is_freeze;
35181
35182 DUK_ASSERT_TOP(ctx, 1);
35183
35184 is_freeze = (duk_bool_t) duk_get_current_magic(ctx);
35185 if (duk_is_buffer(ctx, 0)) {
35186 /* Plain buffer: already sealed, but not frozen (and can't be frozen
35187 * because index properties can't be made non-writable.
35188 */
35189 if (is_freeze) {
35190 goto fail_cannot_freeze;
35191 }
35192 return 1;
35193 } else if (duk_is_lightfunc(ctx, 0)) {
35194 /* Lightfunc: already sealed and frozen, success. */
35195 return 1;
35196 }
35197#if 0
35198 /* Seal/freeze are quite rare in practice so it'd be nice to get the
35199 * correct behavior simply via automatic promotion (at the cost of some
35200 * memory churn). However, the promoted objects don't behave the same,
35201 * e.g. promoted lightfuncs are extensible.
35202 */
35203 h = duk_require_hobject_promote_mask(ctx, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
35204#endif
35205
35206 h = duk_get_hobject(ctx, 0);
35207 if (h == NULL) {
35208 /* ES2015 Sections 19.1.2.5, 19.1.2.17 */
35209 return 1;
35210 }
35211
35212 if (is_freeze && DUK_HOBJECT_IS_BUFOBJ(h)) {
35213 /* Buffer objects cannot be frozen because there's no internal
35214 * support for making virtual array indices non-writable.
35215 */
35216 DUK_DD(DUK_DDPRINT("cannot freeze a buffer object"));
35217 goto fail_cannot_freeze;
35218 }
35219
35220 duk_hobject_object_seal_freeze_helper(thr, h, is_freeze);
35221
35222 /* Sealed and frozen objects cannot gain any more properties,
35223 * so this is a good time to compact them.
35224 */
35225 duk_hobject_compact_props(thr, h);
35226 return 1;
35227
35228 fail_cannot_freeze:
35229 DUK_DCERROR_TYPE_INVALID_ARGS(thr); /* XXX: proper error message */
35230}
35231#endif /* DUK_USE_OBJECT_BUILTIN */
35232
35233#if defined(DUK_USE_OBJECT_BUILTIN)
35234DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_sealed_frozen_shared(duk_context *ctx) {
35235 duk_hobject *h;
35236 duk_bool_t is_frozen;
35237 duk_uint_t mask;
35238
35239 is_frozen = duk_get_current_magic(ctx);
35240 mask = duk_get_type_mask(ctx, 0);
35241 if (mask & (DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER)) {
35242 DUK_ASSERT(is_frozen == 0 || is_frozen == 1);
35243 duk_push_boolean(ctx, (mask & DUK_TYPE_MASK_LIGHTFUNC) ?
35244 1 : /* lightfunc always frozen and sealed */
35245 (is_frozen ^ 1)); /* buffer sealed but not frozen (index props writable) */
35246 } else {
35247 /* ES2015 Sections 19.1.2.12, 19.1.2.13: anything other than an object
35248 * is considered to be already sealed and frozen.
35249 */
35250 h = duk_get_hobject(ctx, 0);
35251 duk_push_boolean(ctx, (h == NULL) ||
35252 duk_hobject_object_is_sealed_frozen_helper((duk_hthread *) ctx, h, is_frozen /*is_frozen*/));
35253 }
35254 return 1;
35255}
35256#endif /* DUK_USE_OBJECT_BUILTIN */
35257
35258#if defined(DUK_USE_OBJECT_BUILTIN)
35259DUK_INTERNAL duk_ret_t duk_bi_object_prototype_to_locale_string(duk_context *ctx) {
35260 DUK_ASSERT_TOP(ctx, 0);
35261 (void) duk_push_this_coercible_to_object(ctx);
35262 duk_get_prop_stridx_short(ctx, 0, DUK_STRIDX_TO_STRING);
35263#if 0 /* This is mentioned explicitly in the E5.1 spec, but duk_call_method() checks for it in practice. */
35264 duk_require_callable(ctx, 1);
35265#endif
35266 duk_dup_0(ctx); /* -> [ O toString O ] */
35267 duk_call_method(ctx, 0); /* XXX: call method tail call? */
35268 return 1;
35269}
35270#endif /* DUK_USE_OBJECT_BUILTIN */
35271
35272#if defined(DUK_USE_OBJECT_BUILTIN)
35273DUK_INTERNAL duk_ret_t duk_bi_object_prototype_value_of(duk_context *ctx) {
35274 /* For lightfuncs and plain buffers, returns Object() coerced. */
35275 (void) duk_push_this_coercible_to_object(ctx);
35276 return 1;
35277}
35278#endif /* DUK_USE_OBJECT_BUILTIN */
35279
35280#if defined(DUK_USE_OBJECT_BUILTIN)
35281DUK_INTERNAL duk_ret_t duk_bi_object_prototype_is_prototype_of(duk_context *ctx) {
35282 duk_hthread *thr = (duk_hthread *) ctx;
35283 duk_hobject *h_v;
35284 duk_hobject *h_obj;
35285
35286 DUK_ASSERT_TOP(ctx, 1);
35287
35288 h_v = duk_get_hobject(ctx, 0);
35289 if (!h_v) {
35290 duk_push_false(ctx); /* XXX: tail call: return duk_push_false(ctx) */
35291 return 1;
35292 }
35293
35294 h_obj = duk_push_this_coercible_to_object(ctx);
35295 DUK_ASSERT(h_obj != NULL);
35296
35297 /* E5.1 Section 15.2.4.6, step 3.a, lookup proto once before compare.
35298 * Prototype loops should cause an error to be thrown.
35299 */
35300 duk_push_boolean(ctx, duk_hobject_prototype_chain_contains(thr, DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_v), h_obj, 0 /*ignore_loop*/));
35301 return 1;
35302}
35303#endif /* DUK_USE_OBJECT_BUILTIN */
35304
35305#if defined(DUK_USE_OBJECT_BUILTIN)
35306DUK_INTERNAL duk_ret_t duk_bi_object_prototype_has_own_property(duk_context *ctx) {
35307 return duk_hobject_object_ownprop_helper(ctx, 0 /*required_desc_flags*/);
35308}
35309#endif /* DUK_USE_OBJECT_BUILTIN */
35310
35311#if defined(DUK_USE_OBJECT_BUILTIN)
35312DUK_INTERNAL duk_ret_t duk_bi_object_prototype_property_is_enumerable(duk_context *ctx) {
35313 return duk_hobject_object_ownprop_helper(ctx, DUK_PROPDESC_FLAG_ENUMERABLE /*required_desc_flags*/);
35314}
35315#endif /* DUK_USE_OBJECT_BUILTIN */
35316
35317#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
35318/* Shared helper to implement Object.getPrototypeOf,
35319 * Object.prototype.__proto__ getter, and Reflect.getPrototypeOf.
35320 *
35321 * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__
35322 */
35323DUK_INTERNAL duk_ret_t duk_bi_object_getprototype_shared(duk_context *ctx) {
35324 /*
35325 * magic = 0: __proto__ getter
35326 * magic = 1: Object.getPrototypeOf()
35327 * magic = 2: Reflect.getPrototypeOf()
35328 */
35329
35330 duk_hthread *thr = (duk_hthread *) ctx;
35331 duk_hobject *h;
35332 duk_hobject *proto;
35333 duk_tval *tv;
35334 duk_int_t magic;
35335
35336 magic = duk_get_current_magic(ctx);
35337
35338 if (magic == 0) {
35339 DUK_ASSERT_TOP(ctx, 0);
35340 duk_push_this_coercible_to_object(ctx);
35341 }
35342 DUK_ASSERT(duk_get_top(ctx) >= 1);
35343 if (magic < 2) {
35344 /* ES2015 Section 19.1.2.9, step 1 */
35345 duk_to_object(ctx, 0);
35346 }
35347 tv = DUK_GET_TVAL_POSIDX(ctx, 0);
35348
35349 switch (DUK_TVAL_GET_TAG(tv)) {
35350 case DUK_TAG_BUFFER:
35351 proto = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE];
35352 break;
35353 case DUK_TAG_LIGHTFUNC:
35354 proto = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
35355 break;
35356 case DUK_TAG_OBJECT:
35357 h = DUK_TVAL_GET_OBJECT(tv);
35358 proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
35359 break;
35360 default:
35361 /* This implicitly handles CheckObjectCoercible() caused
35362 * TypeError.
35363 */
35364 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
35365 }
35366 if (proto != NULL) {
35367 duk_push_hobject(ctx, proto);
35368 } else {
35369 duk_push_null(ctx);
35370 }
35371 return 1;
35372}
35373#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
35374
35375#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
35376/* Shared helper to implement ES2015 Object.setPrototypeOf,
35377 * Object.prototype.__proto__ setter, and Reflect.setPrototypeOf.
35378 *
35379 * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__
35380 * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-object.setprototypeof
35381 */
35382DUK_INTERNAL duk_ret_t duk_bi_object_setprototype_shared(duk_context *ctx) {
35383 /*
35384 * magic = 0: __proto__ setter
35385 * magic = 1: Object.setPrototypeOf()
35386 * magic = 2: Reflect.setPrototypeOf()
35387 */
35388
35389 duk_hthread *thr = (duk_hthread *) ctx;
35390 duk_hobject *h_obj;
35391 duk_hobject *h_new_proto;
35392 duk_hobject *h_curr;
35393 duk_ret_t ret_success = 1; /* retval for success path */
35394 duk_uint_t mask;
35395 duk_int_t magic;
35396
35397 /* Preliminaries for __proto__ and setPrototypeOf (E6 19.1.2.18 steps 1-4). */
35398 magic = duk_get_current_magic(ctx);
35399 if (magic == 0) {
35400 duk_push_this_check_object_coercible(ctx);
35401 duk_insert(ctx, 0);
35402 if (!duk_check_type_mask(ctx, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT)) {
35403 return 0;
35404 }
35405
35406 /* __proto__ setter returns 'undefined' on success unlike the
35407 * setPrototypeOf() call which returns the target object.
35408 */
35409 ret_success = 0;
35410 } else {
35411 if (magic == 1) {
35412 duk_require_object_coercible(ctx, 0);
35413 } else {
35414 duk_require_hobject_accept_mask(ctx, 0,
35415 DUK_TYPE_MASK_LIGHTFUNC |
35416 DUK_TYPE_MASK_BUFFER);
35417 }
35418 duk_require_type_mask(ctx, 1, DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_OBJECT);
35419 }
35420
35421 h_new_proto = duk_get_hobject(ctx, 1);
35422 /* h_new_proto may be NULL */
35423
35424 mask = duk_get_type_mask(ctx, 0);
35425 if (mask & (DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER)) {
35426 duk_hobject *curr_proto;
35427 curr_proto = thr->builtins[(mask & DUK_TYPE_MASK_LIGHTFUNC) ?
35428 DUK_BIDX_FUNCTION_PROTOTYPE :
35429 DUK_BIDX_UINT8ARRAY_PROTOTYPE];
35430 if (h_new_proto == curr_proto) {
35431 goto skip;
35432 }
35433 goto fail_nonextensible;
35434 }
35435 h_obj = duk_get_hobject(ctx, 0);
35436 if (h_obj == NULL) {
35437 goto skip;
35438 }
35439 DUK_ASSERT(h_obj != NULL);
35440
35441 /* [[SetPrototypeOf]] standard behavior, E6 9.1.2. */
35442 /* TODO: implement Proxy object support here */
35443
35444 if (h_new_proto == DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_obj)) {
35445 goto skip;
35446 }
35447 if (!DUK_HOBJECT_HAS_EXTENSIBLE(h_obj)) {
35448 goto fail_nonextensible;
35449 }
35450 for (h_curr = h_new_proto; h_curr != NULL; h_curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h_curr)) {
35451 /* Loop prevention. */
35452 if (h_curr == h_obj) {
35453 goto fail_loop;
35454 }
35455 }
35456 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h_obj, h_new_proto);
35457 /* fall thru */
35458
35459 skip:
35460 duk_set_top(ctx, 1);
35461 if (magic == 2) {
35462 duk_push_true(ctx);
35463 }
35464 return ret_success;
35465
35466 fail_nonextensible:
35467 fail_loop:
35468 if (magic != 2) {
35469 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
35470 } else {
35471 duk_push_false(ctx);
35472 return 1;
35473 }
35474}
35475#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
35476
35477#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
35478DUK_INTERNAL duk_ret_t duk_bi_object_constructor_define_property(duk_context *ctx) {
35479 /*
35480 * magic = 0: Object.defineProperty()
35481 * magic = 1: Reflect.defineProperty()
35482 */
35483
35484 duk_hobject *obj;
35486 duk_hobject *get;
35487 duk_hobject *set;
35488 duk_idx_t idx_value;
35489 duk_uint_t defprop_flags;
35490 duk_int_t magic;
35491 duk_bool_t throw_flag;
35492 duk_bool_t ret;
35493
35494 DUK_ASSERT(ctx != NULL);
35495
35496 DUK_DDD(DUK_DDDPRINT("Object.defineProperty(): ctx=%p obj=%!T key=%!T desc=%!T",
35497 (void *) ctx,
35498 (duk_tval *) duk_get_tval(ctx, 0),
35499 (duk_tval *) duk_get_tval(ctx, 1),
35500 (duk_tval *) duk_get_tval(ctx, 2)));
35501
35502 /* [ obj key desc ] */
35503
35504 magic = duk_get_current_magic(ctx);
35505
35506 /* Lightfuncs are currently supported by coercing to a temporary
35507 * Function object; changes will be allowed (the coerced value is
35508 * extensible) but will be lost. Same for plain buffers.
35509 */
35510 obj = duk_require_hobject_promote_mask(ctx, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
35511 DUK_ASSERT(obj != NULL);
35512 key = duk_to_property_key_hstring(ctx, 1);
35513 (void) duk_require_hobject(ctx, 2);
35514
35515 DUK_ASSERT(obj != NULL);
35516 DUK_ASSERT(key != NULL);
35517 DUK_ASSERT(duk_get_hobject(ctx, 2) != NULL);
35518
35519 /*
35520 * Validate and convert argument property descriptor (an Ecmascript
35521 * object) into a set of defprop_flags and possibly property value,
35522 * getter, and/or setter values on the value stack.
35523 *
35524 * Lightfunc set/get values are coerced to full Functions.
35525 */
35526
35527 duk_hobject_prepare_property_descriptor(ctx,
35528 2 /*idx_desc*/,
35529 &defprop_flags,
35530 &idx_value,
35531 &get,
35532 &set);
35533
35534 /*
35535 * Use Object.defineProperty() helper for the actual operation.
35536 */
35537
35538 DUK_ASSERT(magic == 0 || magic == 1);
35539 throw_flag = magic ^ 1;
35540 ret = duk_hobject_define_property_helper(ctx,
35541 defprop_flags,
35542 obj,
35543 key,
35544 idx_value,
35545 get,
35546 set,
35547 throw_flag);
35548
35549 /* Ignore the normalize/validate helper outputs on the value stack,
35550 * they're popped automatically.
35551 */
35552
35553 if (magic == 0) {
35554 /* Object.defineProperty(): return target object. */
35555 duk_push_hobject(ctx, obj);
35556 } else {
35557 /* Reflect.defineProperty(): return success/fail. */
35558 duk_push_boolean(ctx, ret);
35559 }
35560 return 1;
35561}
35562#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
35563
35564#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
35565DUK_INTERNAL duk_ret_t duk_bi_object_constructor_get_own_property_descriptor(duk_context *ctx) {
35566 DUK_ASSERT_TOP(ctx, 2);
35567
35568 /* ES2015 Section 19.1.2.6, step 1 */
35569 if (duk_get_current_magic(ctx) == 0) {
35570 duk_to_object(ctx, 0);
35571 }
35572
35573 /* [ obj key ] */
35574
35575 duk_hobject_object_get_own_property_descriptor(ctx, -2);
35576 return 1;
35577}
35578#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
35579
35580#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
35581DUK_INTERNAL duk_ret_t duk_bi_object_constructor_is_extensible(duk_context *ctx) {
35582 /*
35583 * magic = 0: Object.isExtensible()
35584 * magic = 1: Reflect.isExtensible()
35585 */
35586
35587 duk_hobject *h;
35588
35589 if (duk_get_current_magic(ctx) == 0) {
35590 h = duk_get_hobject(ctx, 0);
35591 } else {
35592 /* Reflect.isExtensible(): throw if non-object, but we accept lightfuncs
35593 * and plain buffers here because they pretend to be objects.
35594 */
35595 h = duk_require_hobject_accept_mask(ctx, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
35596 }
35597
35598 duk_push_boolean(ctx, (h != NULL) && DUK_HOBJECT_HAS_EXTENSIBLE(h));
35599 return 1;
35600}
35601#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
35602
35603#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
35604/* Shared helper for various key/symbol listings, magic:
35605 * 0=Object.keys()
35606 * 1=Object.getOwnPropertyNames(),
35607 * 2=Object.getOwnPropertySymbols(),
35608 * 3=Reflect.ownKeys()
35609 */
35610DUK_LOCAL const duk_small_uint_t duk__object_keys_enum_flags[4] = {
35611 /* Object.keys() */
35612 DUK_ENUM_OWN_PROPERTIES_ONLY |
35613 DUK_ENUM_NO_PROXY_BEHAVIOR,
35614
35615 /* Object.getOwnPropertyNames() */
35616 DUK_ENUM_INCLUDE_NONENUMERABLE |
35617 DUK_ENUM_OWN_PROPERTIES_ONLY |
35618 DUK_ENUM_NO_PROXY_BEHAVIOR,
35619
35620 /* Object.getOwnPropertySymbols() */
35621 DUK_ENUM_INCLUDE_SYMBOLS |
35622 DUK_ENUM_OWN_PROPERTIES_ONLY |
35623 DUK_ENUM_EXCLUDE_STRINGS |
35624 DUK_ENUM_INCLUDE_NONENUMERABLE |
35625 DUK_ENUM_NO_PROXY_BEHAVIOR,
35626
35627 /* Reflect.ownKeys() */
35628 DUK_ENUM_INCLUDE_SYMBOLS |
35629 DUK_ENUM_OWN_PROPERTIES_ONLY |
35630 DUK_ENUM_INCLUDE_NONENUMERABLE |
35631 DUK_ENUM_NO_PROXY_BEHAVIOR
35632};
35633
35634DUK_INTERNAL duk_ret_t duk_bi_object_constructor_keys_shared(duk_context *ctx) {
35635 duk_hthread *thr = (duk_hthread *) ctx;
35636 duk_hobject *obj;
35637#if defined(DUK_USE_ES6_PROXY)
35638 duk_hobject *h_proxy_target;
35639 duk_hobject *h_proxy_handler;
35640 duk_hobject *h_trap_result;
35641#endif
35642 duk_small_uint_t enum_flags;
35643 duk_int_t magic;
35644
35645 DUK_ASSERT_TOP(ctx, 1);
35646 DUK_UNREF(thr);
35647
35648 magic = duk_get_current_magic(ctx);
35649 if (magic == 3) {
35650 /* ES2015 Section 26.1.11 requires a TypeError for non-objects. Lightfuncs
35651 * and plain buffers pretend to be objects, so accept those too.
35652 */
35653 obj = duk_require_hobject_promote_mask(ctx, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
35654 } else {
35655 /* ES2015: ToObject coerce. */
35656 obj = duk_to_hobject(ctx, 0);
35657 }
35658 DUK_ASSERT(obj != NULL);
35659 DUK_UNREF(obj);
35660
35661 /* XXX: proxy chains */
35662
35663#if defined(DUK_USE_ES6_PROXY)
35664 /* XXX: better sharing of code between proxy target call sites */
35665 if (DUK_LIKELY(!duk_hobject_proxy_check(thr,
35666 obj,
35667 &h_proxy_target,
35668 &h_proxy_handler))) {
35669 goto skip_proxy;
35670 }
35671
35672 duk_push_hobject(ctx, h_proxy_handler);
35673 if (!duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_OWN_KEYS)) {
35674 /* Careful with reachability here: don't pop 'obj' before pushing
35675 * proxy target.
35676 */
35677 DUK_DDD(DUK_DDDPRINT("no ownKeys trap, get keys of target instead"));
35678 duk_pop_2(ctx);
35679 duk_push_hobject(ctx, h_proxy_target);
35680 duk_replace(ctx, 0);
35681 DUK_ASSERT_TOP(ctx, 1);
35682 goto skip_proxy;
35683 }
35684
35685 /* [ obj handler trap ] */
35686 duk_insert(ctx, -2);
35687 duk_push_hobject(ctx, h_proxy_target); /* -> [ obj trap handler target ] */
35688 duk_call_method(ctx, 1 /*nargs*/); /* -> [ obj trap_result ] */
35689 h_trap_result = duk_require_hobject(ctx, -1);
35690 DUK_UNREF(h_trap_result);
35691
35692 magic = duk_get_current_magic(ctx);
35693 DUK_ASSERT(magic >= 0 && magic < (duk_int_t) (sizeof(duk__object_keys_enum_flags) / sizeof(duk_small_uint_t)));
35694 enum_flags = duk__object_keys_enum_flags[magic];
35695
35696 duk_proxy_ownkeys_postprocess(ctx, h_proxy_target, enum_flags);
35697 return 1;
35698
35699 skip_proxy:
35700#endif /* DUK_USE_ES6_PROXY */
35701
35702 DUK_ASSERT_TOP(ctx, 1);
35703 magic = duk_get_current_magic(ctx);
35704 DUK_ASSERT(magic >= 0 && magic < (duk_int_t) (sizeof(duk__object_keys_enum_flags) / sizeof(duk_small_uint_t)));
35705 enum_flags = duk__object_keys_enum_flags[magic];
35706 return duk_hobject_get_enumerated_keys(ctx, enum_flags);
35707}
35708#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
35709
35710#if defined(DUK_USE_OBJECT_BUILTIN) || defined(DUK_USE_REFLECT_BUILTIN)
35711DUK_INTERNAL duk_ret_t duk_bi_object_constructor_prevent_extensions(duk_context *ctx) {
35712 /*
35713 * magic = 0: Object.preventExtensions()
35714 * magic = 1: Reflect.preventExtensions()
35715 */
35716
35717 duk_hthread *thr = (duk_hthread *) ctx;
35718 duk_hobject *h;
35719 duk_uint_t mask;
35720 duk_int_t magic;
35721
35722 magic = duk_get_current_magic(ctx);
35723
35724 /* Silent success for lightfuncs and plain buffers always. */
35725 mask = DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER;
35726
35727 /* Object.preventExtensions() silent success for non-object. */
35728 if (magic == 0) {
35729 mask |= DUK_TYPE_MASK_UNDEFINED |
35730 DUK_TYPE_MASK_NULL |
35731 DUK_TYPE_MASK_BOOLEAN |
35732 DUK_TYPE_MASK_NUMBER |
35733 DUK_TYPE_MASK_STRING |
35734 DUK_TYPE_MASK_POINTER;
35735 }
35736
35737 if (duk_check_type_mask(ctx, 0, mask)) {
35738 /* Not an object, already non-extensible so always success. */
35739 goto done;
35740 }
35741 h = duk_require_hobject(ctx, 0);
35742 DUK_ASSERT(h != NULL);
35743
35744 DUK_HOBJECT_CLEAR_EXTENSIBLE(h);
35745
35746 /* A non-extensible object cannot gain any more properties,
35747 * so this is a good time to compact.
35748 */
35749 duk_hobject_compact_props(thr, h);
35750
35751 done:
35752 if (magic == 1) {
35753 duk_push_true(ctx);
35754 }
35755 return 1;
35756}
35757#endif /* DUK_USE_OBJECT_BUILTIN || DUK_USE_REFLECT_BUILTIN */
35758/*
35759 * Pointer built-ins
35760 */
35761
35762/* #include duk_internal.h -> already included */
35763
35764/*
35765 * Constructor
35766 */
35767
35768DUK_INTERNAL duk_ret_t duk_bi_pointer_constructor(duk_context *ctx) {
35769 /* XXX: this behavior is quite useless now; it would be nice to be able
35770 * to create pointer values from e.g. numbers or strings. Numbers are
35771 * problematic on 64-bit platforms though. Hex encoded strings?
35772 */
35773 if (duk_get_top(ctx) == 0) {
35774 duk_push_pointer(ctx, NULL);
35775 } else {
35776 duk_to_pointer(ctx, 0);
35777 }
35778 DUK_ASSERT(duk_is_pointer(ctx, 0));
35779 duk_set_top(ctx, 1);
35780
35781 if (duk_is_constructor_call(ctx)) {
35782 (void) duk_push_object_helper(ctx,
35783 DUK_HOBJECT_FLAG_EXTENSIBLE |
35784 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_POINTER),
35785 DUK_BIDX_POINTER_PROTOTYPE);
35786
35787 /* Pointer object internal value is immutable */
35788 duk_dup_0(ctx);
35789 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
35790 }
35791 /* Note: unbalanced stack on purpose */
35792
35793 return 1;
35794}
35795
35796/*
35797 * toString(), valueOf()
35798 */
35799
35800DUK_INTERNAL duk_ret_t duk_bi_pointer_prototype_tostring_shared(duk_context *ctx) {
35801 duk_tval *tv;
35802 duk_small_int_t to_string = duk_get_current_magic(ctx);
35803
35804 duk_push_this(ctx);
35805 tv = duk_require_tval(ctx, -1);
35806 DUK_ASSERT(tv != NULL);
35807
35808 if (DUK_TVAL_IS_POINTER(tv)) {
35809 /* nop */
35810 } else if (DUK_TVAL_IS_OBJECT(tv)) {
35811 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
35812 DUK_ASSERT(h != NULL);
35813
35814 /* Must be a "pointer object", i.e. class "Pointer" */
35815 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_POINTER) {
35816 goto type_error;
35817 }
35818
35819 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_VALUE);
35820 } else {
35821 goto type_error;
35822 }
35823
35824 if (to_string) {
35825 duk_to_string(ctx, -1);
35826 }
35827 return 1;
35828
35829 type_error:
35830 DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
35831}
35832/*
35833 * Proxy built-in (ES2015)
35834 */
35835
35836/* #include duk_internal.h -> already included */
35837
35838#if defined(DUK_USE_ES6_PROXY)
35839/* Post-process a Proxy ownKeys() result at stack top. Push a cleaned up
35840 * array of valid result keys (strings or symbols). TypeError for invalid
35841 * values. Flags are shared with duk_enum().
35842 */
35843DUK_INTERNAL void duk_proxy_ownkeys_postprocess(duk_context *ctx, duk_hobject *h_proxy_target, duk_uint_t flags) {
35844 duk_hthread *thr = (duk_hthread *) ctx;
35845 duk_uarridx_t i, len, idx;
35846 duk_propdesc desc;
35847
35848 DUK_ASSERT_CTX_VALID(ctx);
35849 DUK_ASSERT(h_proxy_target != NULL);
35850
35851 len = (duk_uarridx_t) duk_get_length(ctx, -1);
35852 idx = 0;
35853 duk_push_array(ctx);
35854 /* XXX: preallocated dense array, fill in directly */
35855 for (i = 0; i < len; i++) {
35856 duk_hstring *h;
35857
35858 /* [ obj trap_result res_arr ] */
35859 (void) duk_get_prop_index(ctx, -2, i);
35860 h = duk_get_hstring(ctx, -1);
35861 if (h == NULL) {
35862 DUK_ERROR_TYPE_INVALID_TRAP_RESULT(thr);
35863 }
35864
35865 if (!(flags & DUK_ENUM_INCLUDE_NONENUMERABLE)) {
35866 /* No support for 'getOwnPropertyDescriptor' trap yet,
35867 * so check enumerability always from target object
35868 * descriptor.
35869 */
35870 if (duk_hobject_get_own_propdesc(thr, h_proxy_target, duk_known_hstring(ctx, -1), &desc, 0 /*flags*/)) {
35871 if ((desc.flags & DUK_PROPDESC_FLAG_ENUMERABLE) == 0) {
35872 DUK_DDD(DUK_DDDPRINT("ignore non-enumerable property: %!T", duk_get_tval(ctx, -1)));
35873 goto skip_key;
35874 }
35875 } else {
35876 DUK_DDD(DUK_DDDPRINT("ignore non-existent property: %!T", duk_get_tval(ctx, -1)));
35877 goto skip_key;
35878 }
35879 }
35880 if (DUK_HSTRING_HAS_SYMBOL(h)) {
35881 if (!(flags & DUK_ENUM_INCLUDE_SYMBOLS)) {
35882 DUK_DDD(DUK_DDDPRINT("ignore symbol property: %!T", duk_get_tval(ctx, -1)));
35883 goto skip_key;
35884 }
35885 if (DUK_HSTRING_HAS_HIDDEN(h) && !(flags & DUK_ENUM_INCLUDE_HIDDEN)) {
35886 DUK_DDD(DUK_DDDPRINT("ignore hidden symbol property: %!T", duk_get_tval(ctx, -1)));
35887 goto skip_key;
35888 }
35889 } else {
35890 if (flags & DUK_ENUM_EXCLUDE_STRINGS) {
35891 DUK_DDD(DUK_DDDPRINT("ignore string property: %!T", duk_get_tval(ctx, -1)));
35892 goto skip_key;
35893 }
35894 }
35895
35896 /* [ obj trap_result res_arr propname ] */
35897 duk_put_prop_index(ctx, -2, idx++);
35898 continue;
35899
35900 skip_key:
35901 duk_pop(ctx);
35902 continue;
35903 }
35904
35905 /* XXX: Missing trap result validation for non-configurable target keys
35906 * (must be present), for non-extensible target all target keys must be
35907 * present and no extra keys can be present.
35908 * http://www.ecma-international.org/ecma-262/6.0/#sec-proxy-object-internal-methods-and-internal-slots-ownpropertykeys
35909 */
35910
35911 /* XXX: The key enumerability check should trigger the "getOwnPropertyDescriptor"
35912 * trap which has not yet been implemented. In the absence of such a trap,
35913 * the enumerability should be checked from the target object; this is
35914 * handled above.
35915 */
35916}
35917#endif /* DUK_USE_ES6_PROXY */
35918
35919#if defined(DUK_USE_ES6_PROXY)
35920DUK_INTERNAL duk_ret_t duk_bi_proxy_constructor(duk_context *ctx) {
35921 duk_hobject *h_target;
35922 duk_hobject *h_handler;
35923
35924 duk_require_constructor_call(ctx);
35925
35926 /* Reject a proxy object as the target because it would need
35927 * special handler in property lookups. (ES2015 has no such restriction)
35928 */
35929 h_target = duk_require_hobject_promote_mask(ctx, 0, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
35930 DUK_ASSERT(h_target != NULL);
35931 if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h_target)) {
35932 goto fail_args;
35933 }
35934
35935 /* Reject a proxy object as the handler because it would cause
35936 * potentially unbounded recursion. (ES2015 has no such restriction)
35937 *
35938 * There's little practical reason to use a lightfunc or a plain
35939 * buffer as the handler table: one could only provide traps via
35940 * their prototype objects (Function.prototype and ArrayBuffer.prototype).
35941 * Even so, as lightfuncs and plain buffers mimic their object
35942 * counterparts, they're promoted and accepted here.
35943 */
35944 h_handler = duk_require_hobject_promote_mask(ctx, 1, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
35945 DUK_ASSERT(h_handler != NULL);
35946 if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h_handler)) {
35947 goto fail_args;
35948 }
35949
35950 /* XXX: the returned value is exotic in ES2015, but we use a
35951 * simple object here with no prototype. Without a prototype,
35952 * ToPrimitive() coercion fails which is a bit confusing.
35953 * No callable check/handling in the current Proxy subset.
35954 */
35955 (void) duk_push_object_helper_proto(ctx,
35956 DUK_HOBJECT_FLAG_EXTENSIBLE |
35957 DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ |
35958 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
35959 NULL);
35960 DUK_ASSERT_TOP(ctx, 3);
35961
35962 /* Make _Target and _Handler non-configurable and non-writable.
35963 * They can still be forcibly changed by C code (both user and
35964 * Duktape internal), but not by Ecmascript code.
35965 */
35966
35967 /* Proxy target */
35968 duk_dup_0(ctx);
35969 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
35970
35971 /* Proxy handler */
35972 duk_dup_1(ctx);
35973 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_HANDLER, DUK_PROPDESC_FLAGS_NONE);
35974
35975 return 1; /* replacement handler */
35976
35977 fail_args:
35978 DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
35979}
35980#endif /* DUK_USE_ES6_PROXY */
35981/*
35982 * 'Reflect' built-in (ES2016 Section 26.1)
35983 * http://www.ecma-international.org/ecma-262/7.0/#sec-reflect-object
35984 *
35985 * Many Reflect built-in functions are provided by shared helpers in
35986 * duk_bi_object.c or duk_bi_function.c.
35987 */
35988
35989/* #include duk_internal.h -> already included */
35990
35991#if defined(DUK_USE_REFLECT_BUILTIN)
35992DUK_INTERNAL duk_ret_t duk_bi_reflect_object_delete_property(duk_context *ctx) {
35993 duk_hthread *thr;
35994 duk_tval *tv_obj;
35995 duk_tval *tv_key;
35996 duk_bool_t ret;
35997
35998 DUK_ASSERT_TOP(ctx, 2);
35999 (void) duk_require_hobject(ctx, 0);
36000 (void) duk_to_string(ctx, 1);
36001
36002 /* [ target key ] */
36003
36004 thr = (duk_hthread *) ctx;
36005 DUK_ASSERT(thr != NULL);
36006 tv_obj = DUK_GET_TVAL_POSIDX(ctx, 0);
36007 tv_key = DUK_GET_TVAL_POSIDX(ctx, 1);
36008 ret = duk_hobject_delprop(thr, tv_obj, tv_key, 0 /*throw_flag*/);
36009 duk_push_boolean(ctx, ret);
36010 return 1;
36011}
36012
36013DUK_INTERNAL duk_ret_t duk_bi_reflect_object_get(duk_context *ctx) {
36014 duk_hthread *thr;
36015 duk_tval *tv_obj;
36016 duk_tval *tv_key;
36017 duk_idx_t nargs;
36018
36019 nargs = duk_get_top_require_min(ctx, 2 /*min_top*/);
36020 (void) duk_require_hobject(ctx, 0);
36021 (void) duk_to_string(ctx, 1);
36022 if (nargs >= 3 && !duk_strict_equals(ctx, 0, 2)) {
36023 /* XXX: [[Get]] receiver currently unsupported */
36024 DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx);
36025 }
36026
36027 /* [ target key receiver? ...? ] */
36028
36029 thr = (duk_hthread *) ctx;
36030 DUK_ASSERT(thr != NULL);
36031 tv_obj = DUK_GET_TVAL_POSIDX(ctx, 0);
36032 tv_key = DUK_GET_TVAL_POSIDX(ctx, 1);
36033 (void) duk_hobject_getprop(thr, tv_obj, tv_key); /* This could also be a duk_get_prop(). */
36034 return 1;
36035}
36036
36037DUK_INTERNAL duk_ret_t duk_bi_reflect_object_has(duk_context *ctx) {
36038 duk_hthread *thr;
36039 duk_tval *tv_obj;
36040 duk_tval *tv_key;
36041 duk_bool_t ret;
36042
36043 DUK_ASSERT_TOP(ctx, 2);
36044 (void) duk_require_hobject(ctx, 0);
36045 (void) duk_to_string(ctx, 1);
36046
36047 /* [ target key ] */
36048
36049 thr = (duk_hthread *) ctx;
36050 DUK_ASSERT(thr != NULL);
36051 tv_obj = DUK_GET_TVAL_POSIDX(ctx, 0);
36052 tv_key = DUK_GET_TVAL_POSIDX(ctx, 1);
36053 ret = duk_hobject_hasprop(thr, tv_obj, tv_key);
36054 duk_push_boolean(ctx, ret);
36055 return 1;
36056}
36057
36058DUK_INTERNAL duk_ret_t duk_bi_reflect_object_set(duk_context *ctx) {
36059 duk_hthread *thr;
36060 duk_tval *tv_obj;
36061 duk_tval *tv_key;
36062 duk_tval *tv_val;
36063 duk_idx_t nargs;
36064 duk_bool_t ret;
36065
36066 nargs = duk_get_top_require_min(ctx, 3 /*min_top*/);
36067 (void) duk_require_hobject(ctx, 0);
36068 (void) duk_to_string(ctx, 1);
36069 if (nargs >= 4 && !duk_strict_equals(ctx, 0, 3)) {
36070 /* XXX: [[Set]] receiver currently unsupported */
36071 DUK_ERROR_UNSUPPORTED((duk_hthread *) ctx);
36072 }
36073
36074 /* [ target key value receiver? ...? ] */
36075
36076 thr = (duk_hthread *) ctx;
36077 DUK_ASSERT(thr != NULL);
36078 tv_obj = DUK_GET_TVAL_POSIDX(ctx, 0);
36079 tv_key = DUK_GET_TVAL_POSIDX(ctx, 1);
36080 tv_val = DUK_GET_TVAL_POSIDX(ctx, 2);
36081 ret = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, 0 /*throw_flag*/);
36082 duk_push_boolean(ctx, ret);
36083 return 1;
36084}
36085#endif /* DUK_USE_REFLECT_BUILTIN */
36086/*
36087 * RegExp built-ins
36088 */
36089
36090/* #include duk_internal.h -> already included */
36091
36092#if defined(DUK_USE_REGEXP_SUPPORT)
36093
36094DUK_LOCAL void duk__get_this_regexp(duk_context *ctx) {
36095 duk_hobject *h;
36096
36097 duk_push_this(ctx);
36098 h = duk_require_hobject_with_class(ctx, -1, DUK_HOBJECT_CLASS_REGEXP);
36099 DUK_ASSERT(h != NULL);
36100 DUK_UNREF(h);
36101 duk_insert(ctx, 0); /* prepend regexp to valstack 0 index */
36102}
36103
36104/* XXX: much to improve (code size) */
36105DUK_INTERNAL duk_ret_t duk_bi_regexp_constructor(duk_context *ctx) {
36106 duk_hthread *thr = (duk_hthread *) ctx;
36107 duk_hobject *h_pattern;
36108
36109 DUK_ASSERT_TOP(ctx, 2);
36110 h_pattern = duk_get_hobject(ctx, 0);
36111
36112 if (!duk_is_constructor_call(ctx) &&
36113 h_pattern != NULL &&
36114 DUK_HOBJECT_GET_CLASS_NUMBER(h_pattern) == DUK_HOBJECT_CLASS_REGEXP &&
36115 duk_is_undefined(ctx, 1)) {
36116 /* Called as a function, pattern has [[Class]] "RegExp" and
36117 * flags is undefined -> return object as is.
36118 */
36119 /* XXX: ES2015 has a NewTarget SameValue() check which is not
36120 * yet implemented.
36121 */
36122 duk_dup_0(ctx);
36123 return 1;
36124 }
36125
36126 /* Else functionality is identical for function call and constructor
36127 * call.
36128 */
36129
36130 if (h_pattern != NULL &&
36131 DUK_HOBJECT_GET_CLASS_NUMBER(h_pattern) == DUK_HOBJECT_CLASS_REGEXP) {
36132 duk_get_prop_stridx_short(ctx, 0, DUK_STRIDX_SOURCE);
36133 if (duk_is_undefined(ctx, 1)) {
36134 /* In ES5 one would need to read the flags individually;
36135 * in ES2015 just read .flags.
36136 */
36137 duk_get_prop_stridx(ctx, 0, DUK_STRIDX_FLAGS);
36138 } else {
36139 /* In ES2015 allowed; overrides argument RegExp flags. */
36140 duk_dup_1(ctx);
36141 }
36142 } else {
36143 if (duk_is_undefined(ctx, 0)) {
36144 duk_push_hstring_empty(ctx);
36145 } else {
36146 duk_dup_0(ctx);
36147 duk_to_string(ctx, -1); /* Rejects Symbols. */
36148 }
36149 if (duk_is_undefined(ctx, 1)) {
36150 duk_push_hstring_empty(ctx);
36151 } else {
36152 duk_dup_1(ctx);
36153 duk_to_string(ctx, -1); /* Rejects Symbols. */
36154 }
36155
36156 /* [ ... pattern flags ] */
36157 }
36158
36159 DUK_DDD(DUK_DDDPRINT("RegExp constructor/function call, pattern=%!T, flags=%!T",
36160 (duk_tval *) duk_get_tval(ctx, -2), (duk_tval *) duk_get_tval(ctx, -1)));
36161
36162 /* [ ... pattern flags ] (both uncoerced) */
36163
36164 duk_to_string(ctx, -2);
36165 duk_to_string(ctx, -1);
36166 duk_regexp_compile(thr);
36167
36168 /* [ ... bytecode escaped_source ] */
36169
36170 duk_regexp_create_instance(thr);
36171
36172 /* [ ... RegExp ] */
36173
36174 return 1;
36175}
36176
36177DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_exec(duk_context *ctx) {
36178 duk__get_this_regexp(ctx);
36179
36180 /* [ regexp input ] */
36181
36182 duk_regexp_match((duk_hthread *) ctx);
36183
36184 /* [ result ] */
36185
36186 return 1;
36187}
36188
36189DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_test(duk_context *ctx) {
36190 duk__get_this_regexp(ctx);
36191
36192 /* [ regexp input ] */
36193
36194 /* result object is created and discarded; wasteful but saves code space */
36195 duk_regexp_match((duk_hthread *) ctx);
36196
36197 /* [ result ] */
36198
36199 duk_push_boolean(ctx, (duk_is_null(ctx, -1) ? 0 : 1));
36200
36201 return 1;
36202}
36203
36204DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_tostring(duk_context *ctx) {
36205 /* This must be generic in ES2015 and later. */
36206 DUK_ASSERT_TOP(ctx, 0);
36207 duk_push_this(ctx);
36208 duk_push_string(ctx, "/");
36209 duk_get_prop_stridx(ctx, 0, DUK_STRIDX_SOURCE);
36210 duk_dup_m2(ctx); /* another "/" */
36211 duk_get_prop_stridx(ctx, 0, DUK_STRIDX_FLAGS);
36212 duk_concat(ctx, 4);
36213 return 1;
36214}
36215
36216DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_flags(duk_context *ctx) {
36217 /* .flags is ES2015 but present even when ES2015 bindings are
36218 * disabled because the constructor relies on it.
36219 */
36220 duk_uint8_t buf[8]; /* enough for all flags + NUL */
36221 duk_uint8_t *p = buf;
36222
36223 /* .flags is generic and works on any object. */
36224 duk_push_this(ctx);
36225 (void) duk_require_hobject(ctx, -1);
36226 if (duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_GLOBAL, NULL)) {
36227 *p++ = DUK_ASC_LC_G;
36228 }
36229 if (duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_IGNORE_CASE, NULL)) {
36230 *p++ = DUK_ASC_LC_I;
36231 }
36232 if (duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_MULTILINE, NULL)) {
36233 *p++ = DUK_ASC_LC_M;
36234 }
36235 /* .unicode: to be added */
36236 /* .sticky: to be added */
36237 *p++ = DUK_ASC_NUL;
36238 DUK_ASSERT((duk_size_t) (p - buf) <= sizeof(buf));
36239
36240 duk_push_string(ctx, (const char *) buf);
36241 return 1;
36242}
36243
36244/* Shared helper for providing .source, .global, .multiline, etc getters. */
36245DUK_INTERNAL duk_ret_t duk_bi_regexp_prototype_shared_getter(duk_context *ctx) {
36246 duk_hthread *thr = (duk_hthread *) ctx;
36247 duk_hstring *h_bc;
36248 duk_small_int_t re_flags;
36249 duk_hobject *h;
36250 duk_int_t magic;
36251
36252 DUK_ASSERT_TOP(ctx, 0);
36253
36254 duk_push_this(ctx);
36255 h = duk_require_hobject(ctx, -1);
36256 magic = duk_get_current_magic(ctx);
36257
36258 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) == DUK_HOBJECT_CLASS_REGEXP) {
36259 duk_get_prop_stridx_short(ctx, 0, DUK_STRIDX_INT_SOURCE);
36260 duk_get_prop_stridx_short(ctx, 0, DUK_STRIDX_INT_BYTECODE);
36261 h_bc = duk_require_hstring(ctx, -1);
36262 re_flags = (duk_small_int_t) DUK_HSTRING_GET_DATA(h_bc)[0]; /* Safe even if h_bc length is 0 (= NUL) */
36263 duk_pop(ctx);
36264 } else if (h == thr->builtins[DUK_BIDX_REGEXP_PROTOTYPE]) {
36265 /* In ES2015 and ES2016 a TypeError would be thrown here.
36266 * However, this had real world issues so ES2017 draft
36267 * allows RegExp.prototype specifically, returning '(?:)'
36268 * for .source and undefined for all flags.
36269 */
36270 if (magic != 16 /* .source */) {
36271 return 0;
36272 }
36273 duk_push_string(ctx, "(?:)"); /* .source handled by switch-case */
36274 re_flags = 0;
36275 } else {
36276 DUK_DCERROR_TYPE_INVALID_ARGS(thr);
36277 }
36278
36279 /* [ regexp source ] */
36280
36281 switch (magic) {
36282 case 0: { /* global */
36283 duk_push_boolean(ctx, (re_flags & DUK_RE_FLAG_GLOBAL));
36284 break;
36285 }
36286 case 1: { /* ignoreCase */
36287 duk_push_boolean(ctx, (re_flags & DUK_RE_FLAG_IGNORE_CASE));
36288 break;
36289 }
36290 case 2: { /* multiline */
36291 duk_push_boolean(ctx, (re_flags & DUK_RE_FLAG_MULTILINE));
36292 break;
36293 }
36294#if 0
36295 /* Don't provide until implemented to avoid interfering with feature
36296 * detection in user code.
36297 */
36298 case 3: /* sticky */
36299 case 4: { /* unicode */
36300 duk_push_false(ctx);
36301 break;
36302 }
36303#endif
36304 default: { /* source */
36305 /* leave 'source' on top */
36306 break;
36307 }
36308 }
36309
36310 return 1;
36311}
36312
36313#endif /* DUK_USE_REGEXP_SUPPORT */
36314/*
36315 * String built-ins
36316 *
36317 * Most String built-ins must only accept strings (or String objects).
36318 * Symbols, represented internally as strings, must be generally rejected.
36319 * The duk_push_this_coercible_to_string() helper does this automatically.
36320 */
36321
36322/* XXX: There are several limitations in the current implementation for
36323 * strings with >= 0x80000000UL characters. In some cases one would need
36324 * to be able to represent the range [-0xffffffff,0xffffffff] and so on.
36325 * Generally character and byte length are assumed to fit into signed 32
36326 * bits (< 0x80000000UL). Places with issues are not marked explicitly
36327 * below in all cases, look for signed type usage (duk_int_t etc) for
36328 * offsets/lengths.
36329 */
36330
36331/* #include duk_internal.h -> already included */
36332
36333#if defined(DUK_USE_STRING_BUILTIN)
36334
36335/*
36336 * Constructor
36337 */
36338
36339DUK_INTERNAL duk_ret_t duk_bi_string_constructor(duk_context *ctx) {
36340 duk_hstring *h;
36341 duk_uint_t flags;
36342
36343 /* String constructor needs to distinguish between an argument not given at all
36344 * vs. given as 'undefined'. We're a vararg function to handle this properly.
36345 */
36346
36347 /* XXX: copy current activation flags to thr, including current magic,
36348 * is_constructor_call etc. This takes a few bytes in duk_hthread but
36349 * makes call sites smaller (there are >30 is_constructor_call and get
36350 * current magic call sites.
36351 */
36352
36353 if (duk_get_top(ctx) == 0) {
36354 duk_push_hstring_empty(ctx);
36355 } else {
36356 h = duk_to_hstring_acceptsymbol(ctx, 0);
36357 if (DUK_HSTRING_HAS_SYMBOL(h) && !duk_is_constructor_call(ctx)) {
36358 duk_push_symbol_descriptive_string(ctx, h);
36359 duk_replace(ctx, 0);
36360 }
36361 }
36362 duk_to_string(ctx, 0); /* catches symbol argument for constructor call */
36363 DUK_ASSERT(duk_is_string(ctx, 0));
36364 duk_set_top(ctx, 1); /* Top may be 1 or larger. */
36365
36366 if (duk_is_constructor_call(ctx)) {
36367 /* String object internal value is immutable */
36368 flags = DUK_HOBJECT_FLAG_EXTENSIBLE |
36369 DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ |
36370 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_STRING);
36371 duk_push_object_helper(ctx, flags, DUK_BIDX_STRING_PROTOTYPE);
36372 duk_dup_0(ctx);
36373 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_VALUE, DUK_PROPDESC_FLAGS_NONE);
36374 }
36375 /* Note: unbalanced stack on purpose */
36376
36377 return 1;
36378}
36379
36380DUK_LOCAL duk_ret_t duk__construct_from_codepoints(duk_context *ctx, duk_bool_t nonbmp) {
36381 duk_hthread *thr = (duk_hthread *) ctx;
36382 duk_bufwriter_ctx bw_alloc;
36384 duk_idx_t i, n;
36385 duk_ucodepoint_t cp;
36386
36387 /* XXX: It would be nice to build the string directly but ToUint16()
36388 * coercion is needed so a generic helper would not be very
36389 * helpful (perhaps coerce the value stack first here and then
36390 * build a string from a duk_tval number sequence in one go?).
36391 */
36392
36393 n = duk_get_top(ctx);
36394
36395 bw = &bw_alloc;
36396 DUK_BW_INIT_PUSHBUF(thr, bw, n); /* initial estimate for ASCII only codepoints */
36397
36398 for (i = 0; i < n; i++) {
36399 /* XXX: could improve bufwriter handling to write multiple codepoints
36400 * with one ensure call but the relative benefit would be quite small.
36401 */
36402
36403 if (nonbmp) {
36404 /* ES2015 requires that (1) SameValue(cp, ToInteger(cp)) and
36405 * (2) cp >= 0 and cp <= 0x10ffff. This check does not
36406 * implement the steps exactly but the outcome should be
36407 * the same.
36408 */
36409 duk_int32_t i32 = 0;
36410 if (!duk_is_whole_get_int32(duk_to_number(ctx, i), &i32) ||
36411 i32 < 0 || i32 > 0x10ffffL) {
36412 DUK_DCERROR_RANGE_INVALID_ARGS((duk_hthread *) ctx);
36413 }
36414 DUK_ASSERT(i32 >= 0 && i32 <= 0x10ffffL);
36415 cp = (duk_ucodepoint_t) i32;
36416 DUK_BW_WRITE_ENSURE_CESU8(thr, bw, cp);
36417 } else {
36418#if defined(DUK_USE_NONSTD_STRING_FROMCHARCODE_32BIT)
36419 /* ToUint16() coercion is mandatory in the E5.1 specification, but
36420 * this non-compliant behavior makes more sense because we support
36421 * non-BMP codepoints. Don't use CESU-8 because that'd create
36422 * surrogate pairs.
36423 */
36424 cp = (duk_ucodepoint_t) duk_to_uint32(ctx, i);
36425 DUK_BW_WRITE_ENSURE_XUTF8(thr, bw, cp);
36426#else
36427 cp = (duk_ucodepoint_t) duk_to_uint16(ctx, i);
36428 DUK_ASSERT(cp >= 0 && cp <= 0x10ffffL);
36429 DUK_BW_WRITE_ENSURE_CESU8(thr, bw, cp);
36430#endif
36431 }
36432 }
36433
36434 DUK_BW_COMPACT(thr, bw);
36435 (void) duk_buffer_to_string(ctx, -1); /* Safe, extended UTF-8 or CESU-8 encoded. */
36436 return 1;
36437}
36438
36439DUK_INTERNAL duk_ret_t duk_bi_string_constructor_from_char_code(duk_context *ctx) {
36440 return duk__construct_from_codepoints(ctx, 0 /*nonbmp*/);
36441}
36442
36443#if defined(DUK_USE_ES6)
36444DUK_INTERNAL duk_ret_t duk_bi_string_constructor_from_code_point(duk_context *ctx) {
36445 return duk__construct_from_codepoints(ctx, 1 /*nonbmp*/);
36446}
36447#endif
36448
36449/*
36450 * toString(), valueOf()
36451 */
36452
36453DUK_INTERNAL duk_ret_t duk_bi_string_prototype_to_string(duk_context *ctx) {
36454 duk_tval *tv;
36455
36456 duk_push_this(ctx);
36457 tv = duk_require_tval(ctx, -1);
36458 DUK_ASSERT(tv != NULL);
36459
36460 if (DUK_TVAL_IS_STRING(tv)) {
36461 /* return as is */
36462 } else if (DUK_TVAL_IS_OBJECT(tv)) {
36463 duk_hobject *h = DUK_TVAL_GET_OBJECT(tv);
36464 DUK_ASSERT(h != NULL);
36465
36466 /* Must be a "string object", i.e. class "String" */
36467 if (DUK_HOBJECT_GET_CLASS_NUMBER(h) != DUK_HOBJECT_CLASS_STRING) {
36468 goto type_error;
36469 }
36470
36471 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_VALUE);
36472 DUK_ASSERT(duk_is_string(ctx, -1));
36473 } else {
36474 goto type_error;
36475 }
36476
36477 (void) duk_require_hstring_notsymbol(ctx, -1); /* Reject symbols (and wrapped symbols). */
36478 return 1;
36479
36480 type_error:
36481 DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
36482}
36483
36484/*
36485 * Character and charcode access
36486 */
36487
36488DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_at(duk_context *ctx) {
36489 duk_int_t pos;
36490
36491 /* XXX: faster implementation */
36492
36493 (void) duk_push_this_coercible_to_string(ctx);
36494 pos = duk_to_int(ctx, 0);
36495 duk_substring(ctx, -1, pos, pos + 1);
36496 return 1;
36497}
36498
36499/* Magic: 0=charCodeAt, 1=codePointAt */
36500DUK_INTERNAL duk_ret_t duk_bi_string_prototype_char_code_at(duk_context *ctx) {
36501 duk_hthread *thr = (duk_hthread *) ctx;
36502 duk_int_t pos;
36503 duk_hstring *h;
36504 duk_bool_t clamped;
36505 duk_uint32_t cp;
36506 duk_int_t magic;
36507
36508 /* XXX: faster implementation */
36509
36510 DUK_DDD(DUK_DDDPRINT("arg=%!T", (duk_tval *) duk_get_tval(ctx, 0)));
36511
36512 h = duk_push_this_coercible_to_string(ctx);
36513 DUK_ASSERT(h != NULL);
36514
36515 pos = duk_to_int_clamped_raw(ctx,
36516 0 /*index*/,
36517 0 /*min(incl)*/,
36518 DUK_HSTRING_GET_CHARLEN(h) - 1 /*max(incl)*/,
36519 &clamped /*out_clamped*/);
36520#if defined(DUK_USE_ES6)
36521 magic = duk_get_current_magic(ctx);
36522#else
36523 DUK_ASSERT(duk_get_current_magic(ctx) == 0);
36524 magic = 0;
36525#endif
36526 if (clamped) {
36527 /* For out-of-bounds indices .charCodeAt() returns NaN and
36528 * .codePointAt() returns undefined.
36529 */
36530 if (magic != 0) {
36531 return 0;
36532 }
36533 duk_push_nan(ctx);
36534 } else {
36535 cp = (duk_uint32_t) duk_hstring_char_code_at_raw(thr, h, pos, (duk_bool_t) magic /*surrogate_aware*/);
36536 duk_push_u32(ctx, cp);
36537 }
36538 return 1;
36539}
36540
36541/*
36542 * substring(), substr(), slice()
36543 */
36544
36545/* XXX: any chance of merging these three similar but still slightly
36546 * different algorithms so that footprint would be reduced?
36547 */
36548
36549DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substring(duk_context *ctx) {
36550 duk_hstring *h;
36551 duk_int_t start_pos, end_pos;
36552 duk_int_t len;
36553
36554 h = duk_push_this_coercible_to_string(ctx);
36555 DUK_ASSERT(h != NULL);
36556 len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
36557
36558 /* [ start end str ] */
36559
36560 start_pos = duk_to_int_clamped(ctx, 0, 0, len);
36561 if (duk_is_undefined(ctx, 1)) {
36562 end_pos = len;
36563 } else {
36564 end_pos = duk_to_int_clamped(ctx, 1, 0, len);
36565 }
36566 DUK_ASSERT(start_pos >= 0 && start_pos <= len);
36567 DUK_ASSERT(end_pos >= 0 && end_pos <= len);
36568
36569 if (start_pos > end_pos) {
36570 duk_int_t tmp = start_pos;
36571 start_pos = end_pos;
36572 end_pos = tmp;
36573 }
36574
36575 DUK_ASSERT(end_pos >= start_pos);
36576
36577 duk_substring(ctx, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
36578 return 1;
36579}
36580
36581#if defined(DUK_USE_SECTION_B)
36582DUK_INTERNAL duk_ret_t duk_bi_string_prototype_substr(duk_context *ctx) {
36583 duk_hstring *h;
36584 duk_int_t start_pos, end_pos;
36585 duk_int_t len;
36586
36587 /* Unlike non-obsolete String calls, substr() algorithm in E5.1
36588 * specification will happily coerce undefined and null to strings
36589 * ("undefined" and "null").
36590 */
36591 duk_push_this(ctx);
36592 h = duk_to_hstring_m1(ctx); /* Reject Symbols. */
36593 DUK_ASSERT(h != NULL);
36594 len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
36595
36596 /* [ start length str ] */
36597
36598 /* The implementation for computing of start_pos and end_pos differs
36599 * from the standard algorithm, but is intended to result in the exactly
36600 * same behavior. This is not always obvious.
36601 */
36602
36603 /* combines steps 2 and 5; -len ensures max() not needed for step 5 */
36604 start_pos = duk_to_int_clamped(ctx, 0, -len, len);
36605 if (start_pos < 0) {
36606 start_pos = len + start_pos;
36607 }
36608 DUK_ASSERT(start_pos >= 0 && start_pos <= len);
36609
36610 /* combines steps 3, 6; step 7 is not needed */
36611 if (duk_is_undefined(ctx, 1)) {
36612 end_pos = len;
36613 } else {
36614 DUK_ASSERT(start_pos <= len);
36615 end_pos = start_pos + duk_to_int_clamped(ctx, 1, 0, len - start_pos);
36616 }
36617 DUK_ASSERT(start_pos >= 0 && start_pos <= len);
36618 DUK_ASSERT(end_pos >= 0 && end_pos <= len);
36619 DUK_ASSERT(end_pos >= start_pos);
36620
36621 duk_substring(ctx, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
36622 return 1;
36623}
36624#endif /* DUK_USE_SECTION_B */
36625
36626DUK_INTERNAL duk_ret_t duk_bi_string_prototype_slice(duk_context *ctx) {
36627 duk_hstring *h;
36628 duk_int_t start_pos, end_pos;
36629 duk_int_t len;
36630
36631 h = duk_push_this_coercible_to_string(ctx);
36632 DUK_ASSERT(h != NULL);
36633 len = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h);
36634
36635 /* [ start end str ] */
36636
36637 start_pos = duk_to_int_clamped(ctx, 0, -len, len);
36638 if (start_pos < 0) {
36639 start_pos = len + start_pos;
36640 }
36641 if (duk_is_undefined(ctx, 1)) {
36642 end_pos = len;
36643 } else {
36644 end_pos = duk_to_int_clamped(ctx, 1, -len, len);
36645 if (end_pos < 0) {
36646 end_pos = len + end_pos;
36647 }
36648 }
36649 DUK_ASSERT(start_pos >= 0 && start_pos <= len);
36650 DUK_ASSERT(end_pos >= 0 && end_pos <= len);
36651
36652 if (end_pos < start_pos) {
36653 end_pos = start_pos;
36654 }
36655
36656 DUK_ASSERT(end_pos >= start_pos);
36657
36658 duk_substring(ctx, -1, (duk_size_t) start_pos, (duk_size_t) end_pos);
36659 return 1;
36660}
36661
36662/*
36663 * Case conversion
36664 */
36665
36666DUK_INTERNAL duk_ret_t duk_bi_string_prototype_caseconv_shared(duk_context *ctx) {
36667 duk_hthread *thr = (duk_hthread *) ctx;
36668 duk_small_int_t uppercase = duk_get_current_magic(ctx);
36669
36670 (void) duk_push_this_coercible_to_string(ctx);
36671 duk_unicode_case_convert_string(thr, (duk_bool_t) uppercase);
36672 return 1;
36673}
36674
36675/*
36676 * indexOf() and lastIndexOf()
36677 */
36678
36679DUK_INTERNAL duk_ret_t duk_bi_string_prototype_indexof_shared(duk_context *ctx) {
36680 duk_hthread *thr = (duk_hthread *) ctx;
36681 duk_hstring *h_this;
36682 duk_hstring *h_search;
36683 duk_int_t clen_this;
36684 duk_int_t cpos;
36685 duk_int_t bpos;
36686 const duk_uint8_t *p_start, *p_end, *p;
36687 const duk_uint8_t *q_start;
36688 duk_int_t q_blen;
36689 duk_uint8_t firstbyte;
36690 duk_uint8_t t;
36691 duk_small_int_t is_lastindexof = duk_get_current_magic(ctx); /* 0=indexOf, 1=lastIndexOf */
36692
36693 h_this = duk_push_this_coercible_to_string(ctx);
36694 DUK_ASSERT(h_this != NULL);
36695 clen_this = (duk_int_t) DUK_HSTRING_GET_CHARLEN(h_this);
36696
36697 h_search = duk_to_hstring(ctx, 0);
36698 DUK_ASSERT(h_search != NULL);
36699 q_start = DUK_HSTRING_GET_DATA(h_search);
36700 q_blen = (duk_int_t) DUK_HSTRING_GET_BYTELEN(h_search);
36701
36702 duk_to_number(ctx, 1);
36703 if (duk_is_nan(ctx, 1) && is_lastindexof) {
36704 /* indexOf: NaN should cause pos to be zero.
36705 * lastIndexOf: NaN should cause pos to be +Infinity
36706 * (and later be clamped to len).
36707 */
36708 cpos = clen_this;
36709 } else {
36710 cpos = duk_to_int_clamped(ctx, 1, 0, clen_this);
36711 }
36712
36713 /* Empty searchstring always matches; cpos must be clamped here.
36714 * (If q_blen were < 0 due to clamped coercion, it would also be
36715 * caught here.)
36716 */
36717 if (q_blen <= 0) {
36718 duk_push_int(ctx, cpos);
36719 return 1;
36720 }
36721 DUK_ASSERT(q_blen > 0);
36722
36723 bpos = (duk_int_t) duk_heap_strcache_offset_char2byte(thr, h_this, (duk_uint32_t) cpos);
36724
36725 p_start = DUK_HSTRING_GET_DATA(h_this);
36726 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_this);
36727 p = p_start + bpos;
36728
36729 /* This loop is optimized for size. For speed, there should be
36730 * two separate loops, and we should ensure that memcmp() can be
36731 * used without an extra "will searchstring fit" check. Doing
36732 * the preconditioning for 'p' and 'p_end' is easy but cpos
36733 * must be updated if 'p' is wound back (backward scanning).
36734 */
36735
36736 firstbyte = q_start[0]; /* leading byte of match string */
36737 while (p <= p_end && p >= p_start) {
36738 t = *p;
36739
36740 /* For Ecmascript strings, this check can only match for
36741 * initial UTF-8 bytes (not continuation bytes). For other
36742 * strings all bets are off.
36743 */
36744
36745 if ((t == firstbyte) && ((duk_size_t) (p_end - p) >= (duk_size_t) q_blen)) {
36746 DUK_ASSERT(q_blen > 0); /* no issues with memcmp() zero size, even if broken */
36747 if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
36748 duk_push_int(ctx, cpos);
36749 return 1;
36750 }
36751 }
36752
36753 /* track cpos while scanning */
36754 if (is_lastindexof) {
36755 /* when going backwards, we decrement cpos 'early';
36756 * 'p' may point to a continuation byte of the char
36757 * at offset 'cpos', but that's OK because we'll
36758 * backtrack all the way to the initial byte.
36759 */
36760 if ((t & 0xc0) != 0x80) {
36761 cpos--;
36762 }
36763 p--;
36764 } else {
36765 if ((t & 0xc0) != 0x80) {
36766 cpos++;
36767 }
36768 p++;
36769 }
36770 }
36771
36772 /* Not found. Empty string case is handled specially above. */
36773 duk_push_int(ctx, -1);
36774 return 1;
36775}
36776
36777/*
36778 * replace()
36779 */
36780
36781/* XXX: the current implementation works but is quite clunky; it compiles
36782 * to almost 1,4kB of x86 code so it needs to be simplified (better approach,
36783 * shared helpers, etc). Some ideas for refactoring:
36784 *
36785 * - a primitive to convert a string into a regexp matcher (reduces matching
36786 * code at the cost of making matching much slower)
36787 * - use replace() as a basic helper for match() and split(), which are both
36788 * much simpler
36789 * - API call to get_prop and to_boolean
36790 */
36791
36792DUK_INTERNAL duk_ret_t duk_bi_string_prototype_replace(duk_context *ctx) {
36793 duk_hthread *thr = (duk_hthread *) ctx;
36794 duk_hstring *h_input;
36795 duk_hstring *h_match;
36796 duk_hstring *h_search;
36797 duk_hobject *h_re;
36798 duk_bufwriter_ctx bw_alloc;
36800#if defined(DUK_USE_REGEXP_SUPPORT)
36801 duk_bool_t is_regexp;
36802 duk_bool_t is_global;
36803#endif
36804 duk_bool_t is_repl_func;
36805 duk_uint32_t match_start_coff, match_start_boff;
36806#if defined(DUK_USE_REGEXP_SUPPORT)
36807 duk_int_t match_caps;
36808#endif
36809 duk_uint32_t prev_match_end_boff;
36810 const duk_uint8_t *r_start, *r_end, *r; /* repl string scan */
36811 duk_size_t tmp_sz;
36812
36813 DUK_ASSERT_TOP(ctx, 2);
36814 h_input = duk_push_this_coercible_to_string(ctx);
36815 DUK_ASSERT(h_input != NULL);
36816
36817 bw = &bw_alloc;
36818 DUK_BW_INIT_PUSHBUF(thr, bw, DUK_HSTRING_GET_BYTELEN(h_input)); /* input size is good output starting point */
36819
36820 DUK_ASSERT_TOP(ctx, 4);
36821
36822 /* stack[0] = search value
36823 * stack[1] = replace value
36824 * stack[2] = input string
36825 * stack[3] = result buffer
36826 */
36827
36828 h_re = duk_get_hobject_with_class(ctx, 0, DUK_HOBJECT_CLASS_REGEXP);
36829 if (h_re) {
36830#if defined(DUK_USE_REGEXP_SUPPORT)
36831 is_regexp = 1;
36832 is_global = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_GLOBAL, NULL);
36833
36834 if (is_global) {
36835 /* start match from beginning */
36836 duk_push_int(ctx, 0);
36837 duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_LAST_INDEX);
36838 }
36839#else /* DUK_USE_REGEXP_SUPPORT */
36840 DUK_DCERROR_UNSUPPORTED(thr);
36841#endif /* DUK_USE_REGEXP_SUPPORT */
36842 } else {
36843 duk_to_string(ctx, 0); /* rejects symbols */
36844#if defined(DUK_USE_REGEXP_SUPPORT)
36845 is_regexp = 0;
36846 is_global = 0;
36847#endif
36848 }
36849
36850 if (duk_is_function(ctx, 1)) {
36851 is_repl_func = 1;
36852 r_start = NULL;
36853 r_end = NULL;
36854 } else {
36855 duk_hstring *h_repl;
36856
36857 is_repl_func = 0;
36858 h_repl = duk_to_hstring(ctx, 1); /* reject symbols */
36859 DUK_ASSERT(h_repl != NULL);
36860 r_start = DUK_HSTRING_GET_DATA(h_repl);
36861 r_end = r_start + DUK_HSTRING_GET_BYTELEN(h_repl);
36862 }
36863
36864 prev_match_end_boff = 0;
36865
36866 for (;;) {
36867 /*
36868 * If matching with a regexp:
36869 * - non-global RegExp: lastIndex not touched on a match, zeroed
36870 * on a non-match
36871 * - global RegExp: on match, lastIndex will be updated by regexp
36872 * executor to point to next char after the matching part (so that
36873 * characters in the matching part are not matched again)
36874 *
36875 * If matching with a string:
36876 * - always non-global match, find first occurrence
36877 *
36878 * We need:
36879 * - The character offset of start-of-match for the replacer function
36880 * - The byte offsets for start-of-match and end-of-match to implement
36881 * the replacement values $&, $`, and $', and to copy non-matching
36882 * input string portions (including header and trailer) verbatim.
36883 *
36884 * NOTE: the E5.1 specification is a bit vague how the RegExp should
36885 * behave in the replacement process; e.g. is matching done first for
36886 * all matches (in the global RegExp case) before any replacer calls
36887 * are made? See: test-bi-string-proto-replace.js for discussion.
36888 */
36889
36890 DUK_ASSERT_TOP(ctx, 4);
36891
36892#if defined(DUK_USE_REGEXP_SUPPORT)
36893 if (is_regexp) {
36894 duk_dup_0(ctx);
36895 duk_dup_2(ctx);
36896 duk_regexp_match(thr); /* [ ... regexp input ] -> [ res_obj ] */
36897 if (!duk_is_object(ctx, -1)) {
36898 duk_pop(ctx);
36899 break;
36900 }
36901
36902 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INDEX);
36903 DUK_ASSERT(duk_is_number(ctx, -1));
36904 match_start_coff = duk_get_int(ctx, -1);
36905 duk_pop(ctx);
36906
36907 duk_get_prop_index(ctx, -1, 0);
36908 DUK_ASSERT(duk_is_string(ctx, -1));
36909 h_match = duk_known_hstring(ctx, -1);
36910 duk_pop(ctx); /* h_match is borrowed, remains reachable through match_obj */
36911
36912 if (DUK_HSTRING_GET_BYTELEN(h_match) == 0) {
36913 /* This should be equivalent to match() algorithm step 8.f.iii.2:
36914 * detect an empty match and allow it, but don't allow it twice.
36915 */
36916 duk_uint32_t last_index;
36917
36918 duk_get_prop_stridx_short(ctx, 0, DUK_STRIDX_LAST_INDEX);
36919 last_index = (duk_uint32_t) duk_get_uint(ctx, -1);
36920 DUK_DDD(DUK_DDDPRINT("empty match, bump lastIndex: %ld -> %ld",
36921 (long) last_index, (long) (last_index + 1)));
36922 duk_pop(ctx);
36923 duk_push_int(ctx, last_index + 1);
36924 duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_LAST_INDEX);
36925 }
36926
36927 DUK_ASSERT(duk_get_length(ctx, -1) <= DUK_INT_MAX); /* string limits */
36928 match_caps = (duk_int_t) duk_get_length(ctx, -1);
36929 } else {
36930#else /* DUK_USE_REGEXP_SUPPORT */
36931 { /* unconditionally */
36932#endif /* DUK_USE_REGEXP_SUPPORT */
36933 const duk_uint8_t *p_start, *p_end, *p; /* input string scan */
36934 const duk_uint8_t *q_start; /* match string */
36935 duk_size_t q_blen;
36936
36937#if defined(DUK_USE_REGEXP_SUPPORT)
36938 DUK_ASSERT(!is_global); /* single match always */
36939#endif
36940
36941 p_start = DUK_HSTRING_GET_DATA(h_input);
36942 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
36943 p = p_start;
36944
36945 h_search = duk_known_hstring(ctx, 0);
36946 q_start = DUK_HSTRING_GET_DATA(h_search);
36947 q_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_search);
36948
36949 p_end -= q_blen; /* ensure full memcmp() fits in while */
36950
36951 match_start_coff = 0;
36952
36953 while (p <= p_end) {
36954 DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input));
36955 if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
36956 duk_dup_0(ctx);
36957 h_match = duk_known_hstring(ctx, -1);
36958#if defined(DUK_USE_REGEXP_SUPPORT)
36959 match_caps = 0;
36960#endif
36961 goto found;
36962 }
36963
36964 /* track utf-8 non-continuation bytes */
36965 if ((p[0] & 0xc0) != 0x80) {
36966 match_start_coff++;
36967 }
36968 p++;
36969 }
36970
36971 /* not found */
36972 break;
36973 }
36974 found:
36975
36976 /* stack[0] = search value
36977 * stack[1] = replace value
36978 * stack[2] = input string
36979 * stack[3] = result buffer
36980 * stack[4] = regexp match OR match string
36981 */
36982
36983 match_start_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff);
36984
36985 tmp_sz = (duk_size_t) (match_start_boff - prev_match_end_boff);
36986 DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff, tmp_sz);
36987
36988 prev_match_end_boff = match_start_boff + DUK_HSTRING_GET_BYTELEN(h_match);
36989
36990 if (is_repl_func) {
36991 duk_idx_t idx_args;
36992 duk_hstring *h_repl;
36993
36994 /* regexp res_obj is at index 4 */
36995
36996 duk_dup_1(ctx);
36997 idx_args = duk_get_top(ctx);
36998
36999#if defined(DUK_USE_REGEXP_SUPPORT)
37000 if (is_regexp) {
37001 duk_int_t idx;
37002 duk_require_stack(ctx, match_caps + 2);
37003 for (idx = 0; idx < match_caps; idx++) {
37004 /* match followed by capture(s) */
37005 duk_get_prop_index(ctx, 4, idx);
37006 }
37007 } else {
37008#else /* DUK_USE_REGEXP_SUPPORT */
37009 { /* unconditionally */
37010#endif /* DUK_USE_REGEXP_SUPPORT */
37011 /* match == search string, by definition */
37012 duk_dup_0(ctx);
37013 }
37014 duk_push_int(ctx, match_start_coff);
37015 duk_dup_2(ctx);
37016
37017 /* [ ... replacer match [captures] match_char_offset input ] */
37018
37019 duk_call(ctx, duk_get_top(ctx) - idx_args);
37020 h_repl = duk_to_hstring_m1(ctx); /* -> [ ... repl_value ] */
37021 DUK_ASSERT(h_repl != NULL);
37022
37023 DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_repl);
37024
37025 duk_pop(ctx); /* repl_value */
37026 } else {
37027 r = r_start;
37028
37029 while (r < r_end) {
37030 duk_int_t ch1;
37031 duk_int_t ch2;
37032#if defined(DUK_USE_REGEXP_SUPPORT)
37033 duk_int_t ch3;
37034#endif
37035 duk_size_t left;
37036
37037 ch1 = *r++;
37038 if (ch1 != DUK_ASC_DOLLAR) {
37039 goto repl_write;
37040 }
37041 left = r_end - r;
37042
37043 if (left <= 0) {
37044 goto repl_write;
37045 }
37046
37047 ch2 = r[0];
37048 switch (ch2) {
37049 case DUK_ASC_DOLLAR: {
37050 ch1 = (1 << 8) + DUK_ASC_DOLLAR;
37051 goto repl_write;
37052 }
37053 case DUK_ASC_AMP: {
37054 DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_match);
37055 r++;
37056 continue;
37057 }
37058 case DUK_ASC_GRAVE: {
37059 tmp_sz = (duk_size_t) match_start_boff;
37060 DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input), tmp_sz);
37061 r++;
37062 continue;
37063 }
37064 case DUK_ASC_SINGLEQUOTE: {
37065 duk_uint32_t match_end_boff;
37066
37067 /* Use match charlen instead of bytelen, just in case the input and
37068 * match codepoint encodings would have different lengths.
37069 */
37070 match_end_boff = duk_heap_strcache_offset_char2byte(thr,
37071 h_input,
37072 match_start_coff + DUK_HSTRING_GET_CHARLEN(h_match));
37073
37074 tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - match_end_boff);
37075 DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + match_end_boff, tmp_sz);
37076 r++;
37077 continue;
37078 }
37079 default: {
37080#if defined(DUK_USE_REGEXP_SUPPORT)
37081 duk_int_t capnum, captmp, capadv;
37082 /* XXX: optional check, match_caps is zero if no regexp,
37083 * so dollar will be interpreted literally anyway.
37084 */
37085
37086 if (!is_regexp) {
37087 goto repl_write;
37088 }
37089
37090 if (!(ch2 >= DUK_ASC_0 && ch2 <= DUK_ASC_9)) {
37091 goto repl_write;
37092 }
37093 capnum = ch2 - DUK_ASC_0;
37094 capadv = 1;
37095
37096 if (left >= 2) {
37097 ch3 = r[1];
37098 if (ch3 >= DUK_ASC_0 && ch3 <= DUK_ASC_9) {
37099 captmp = capnum * 10 + (ch3 - DUK_ASC_0);
37100 if (captmp < match_caps) {
37101 capnum = captmp;
37102 capadv = 2;
37103 }
37104 }
37105 }
37106
37107 if (capnum > 0 && capnum < match_caps) {
37108 DUK_ASSERT(is_regexp != 0); /* match_caps == 0 without regexps */
37109
37110 /* regexp res_obj is at offset 4 */
37111 duk_get_prop_index(ctx, 4, (duk_uarridx_t) capnum);
37112 if (duk_is_string(ctx, -1)) {
37113 duk_hstring *h_tmp_str;
37114
37115 h_tmp_str = duk_known_hstring(ctx, -1);
37116
37117 DUK_BW_WRITE_ENSURE_HSTRING(thr, bw, h_tmp_str);
37118 } else {
37119 /* undefined -> skip (replaced with empty) */
37120 }
37121 duk_pop(ctx);
37122 r += capadv;
37123 continue;
37124 } else {
37125 goto repl_write;
37126 }
37127#else /* DUK_USE_REGEXP_SUPPORT */
37128 goto repl_write; /* unconditionally */
37129#endif /* DUK_USE_REGEXP_SUPPORT */
37130 } /* default case */
37131 } /* switch (ch2) */
37132
37133 repl_write:
37134 /* ch1 = (r_increment << 8) + byte */
37135
37136 DUK_BW_WRITE_ENSURE_U8(thr, bw, (duk_uint8_t) (ch1 & 0xff));
37137 r += ch1 >> 8;
37138 } /* while repl */
37139 } /* if (is_repl_func) */
37140
37141 duk_pop(ctx); /* pop regexp res_obj or match string */
37142
37143#if defined(DUK_USE_REGEXP_SUPPORT)
37144 if (!is_global) {
37145#else
37146 { /* unconditionally; is_global==0 */
37147#endif
37148 break;
37149 }
37150 }
37151
37152 /* trailer */
37153 tmp_sz = (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - prev_match_end_boff);
37154 DUK_BW_WRITE_ENSURE_BYTES(thr, bw, DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff, tmp_sz);
37155
37156 DUK_ASSERT_TOP(ctx, 4);
37157 DUK_BW_COMPACT(thr, bw);
37158 (void) duk_buffer_to_string(ctx, -1); /* Safe if inputs are safe. */
37159 return 1;
37160}
37161
37162/*
37163 * split()
37164 */
37165
37166/* XXX: very messy now, but works; clean up, remove unused variables (nomimally
37167 * used so compiler doesn't complain).
37168 */
37169
37170DUK_INTERNAL duk_ret_t duk_bi_string_prototype_split(duk_context *ctx) {
37171 duk_hthread *thr = (duk_hthread *) ctx;
37172 duk_hstring *h_input;
37173 duk_hstring *h_sep;
37174 duk_uint32_t limit;
37175 duk_uint32_t arr_idx;
37176#if defined(DUK_USE_REGEXP_SUPPORT)
37177 duk_bool_t is_regexp;
37178#endif
37179 duk_bool_t matched; /* set to 1 if any match exists (needed for empty input special case) */
37180 duk_uint32_t prev_match_end_coff, prev_match_end_boff;
37181 duk_uint32_t match_start_boff, match_start_coff;
37182 duk_uint32_t match_end_boff, match_end_coff;
37183
37184 DUK_UNREF(thr);
37185
37186 h_input = duk_push_this_coercible_to_string(ctx);
37187 DUK_ASSERT(h_input != NULL);
37188
37189 duk_push_array(ctx);
37190
37191 if (duk_is_undefined(ctx, 1)) {
37192 limit = 0xffffffffUL;
37193 } else {
37194 limit = duk_to_uint32(ctx, 1);
37195 }
37196
37197 if (limit == 0) {
37198 return 1;
37199 }
37200
37201 /* If the separator is a RegExp, make a "clone" of it. The specification
37202 * algorithm calls [[Match]] directly for specific indices; we emulate this
37203 * by tweaking lastIndex and using a "force global" variant of duk_regexp_match()
37204 * which will use global-style matching even when the RegExp itself is non-global.
37205 */
37206
37207 if (duk_is_undefined(ctx, 0)) {
37208 /* The spec algorithm first does "R = ToString(separator)" before checking
37209 * whether separator is undefined. Since this is side effect free, we can
37210 * skip the ToString() here.
37211 */
37212 duk_dup_2(ctx);
37213 duk_put_prop_index(ctx, 3, 0);
37214 return 1;
37215 } else if (duk_get_hobject_with_class(ctx, 0, DUK_HOBJECT_CLASS_REGEXP) != NULL) {
37216#if defined(DUK_USE_REGEXP_SUPPORT)
37217 duk_push_hobject_bidx(ctx, DUK_BIDX_REGEXP_CONSTRUCTOR);
37218 duk_dup_0(ctx);
37219 duk_new(ctx, 1); /* [ ... RegExp val ] -> [ ... res ] */
37220 duk_replace(ctx, 0);
37221 /* lastIndex is initialized to zero by new RegExp() */
37222 is_regexp = 1;
37223#else
37224 DUK_DCERROR_UNSUPPORTED(thr);
37225#endif
37226 } else {
37227 duk_to_string(ctx, 0);
37228#if defined(DUK_USE_REGEXP_SUPPORT)
37229 is_regexp = 0;
37230#endif
37231 }
37232
37233 /* stack[0] = separator (string or regexp)
37234 * stack[1] = limit
37235 * stack[2] = input string
37236 * stack[3] = result array
37237 */
37238
37239 prev_match_end_boff = 0;
37240 prev_match_end_coff = 0;
37241 arr_idx = 0;
37242 matched = 0;
37243
37244 for (;;) {
37245 /*
37246 * The specification uses RegExp [[Match]] to attempt match at specific
37247 * offsets. We don't have such a primitive, so we use an actual RegExp
37248 * and tweak lastIndex. Since the RegExp may be non-global, we use a
37249 * special variant which forces global-like behavior for matching.
37250 */
37251
37252 DUK_ASSERT_TOP(ctx, 4);
37253
37254#if defined(DUK_USE_REGEXP_SUPPORT)
37255 if (is_regexp) {
37256 duk_dup_0(ctx);
37257 duk_dup_2(ctx);
37258 duk_regexp_match_force_global(thr); /* [ ... regexp input ] -> [ res_obj ] */
37259 if (!duk_is_object(ctx, -1)) {
37260 duk_pop(ctx);
37261 break;
37262 }
37263 matched = 1;
37264
37265 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INDEX);
37266 DUK_ASSERT(duk_is_number(ctx, -1));
37267 match_start_coff = duk_get_int(ctx, -1);
37268 match_start_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_start_coff);
37269 duk_pop(ctx);
37270
37271 if (match_start_coff == DUK_HSTRING_GET_CHARLEN(h_input)) {
37272 /* don't allow an empty match at the end of the string */
37273 duk_pop(ctx);
37274 break;
37275 }
37276
37277 duk_get_prop_stridx_short(ctx, 0, DUK_STRIDX_LAST_INDEX);
37278 DUK_ASSERT(duk_is_number(ctx, -1));
37279 match_end_coff = duk_get_int(ctx, -1);
37280 match_end_boff = duk_heap_strcache_offset_char2byte(thr, h_input, match_end_coff);
37281 duk_pop(ctx);
37282
37283 /* empty match -> bump and continue */
37284 if (prev_match_end_boff == match_end_boff) {
37285 duk_push_int(ctx, match_end_coff + 1);
37286 duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_LAST_INDEX);
37287 duk_pop(ctx);
37288 continue;
37289 }
37290 } else {
37291#else /* DUK_USE_REGEXP_SUPPORT */
37292 { /* unconditionally */
37293#endif /* DUK_USE_REGEXP_SUPPORT */
37294 const duk_uint8_t *p_start, *p_end, *p; /* input string scan */
37295 const duk_uint8_t *q_start; /* match string */
37296 duk_size_t q_blen, q_clen;
37297
37298 p_start = DUK_HSTRING_GET_DATA(h_input);
37299 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h_input);
37300 p = p_start + prev_match_end_boff;
37301
37302 h_sep = duk_known_hstring(ctx, 0); /* symbol already rejected above */
37303 q_start = DUK_HSTRING_GET_DATA(h_sep);
37304 q_blen = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h_sep);
37305 q_clen = (duk_size_t) DUK_HSTRING_GET_CHARLEN(h_sep);
37306
37307 p_end -= q_blen; /* ensure full memcmp() fits in while */
37308
37309 match_start_coff = prev_match_end_coff;
37310
37311 if (q_blen == 0) {
37312 /* Handle empty separator case: it will always match, and always
37313 * triggers the check in step 13.c.iii initially. Note that we
37314 * must skip to either end of string or start of first codepoint,
37315 * skipping over any continuation bytes!
37316 *
37317 * Don't allow an empty string to match at the end of the input.
37318 */
37319
37320 matched = 1; /* empty separator can always match */
37321
37322 match_start_coff++;
37323 p++;
37324 while (p < p_end) {
37325 if ((p[0] & 0xc0) != 0x80) {
37326 goto found;
37327 }
37328 p++;
37329 }
37330 goto not_found;
37331 }
37332
37333 DUK_ASSERT(q_blen > 0 && q_clen > 0);
37334 while (p <= p_end) {
37335 DUK_ASSERT(p + q_blen <= DUK_HSTRING_GET_DATA(h_input) + DUK_HSTRING_GET_BYTELEN(h_input));
37336 DUK_ASSERT(q_blen > 0); /* no issues with empty memcmp() */
37337 if (DUK_MEMCMP((const void *) p, (const void *) q_start, (size_t) q_blen) == 0) {
37338 /* never an empty match, so step 13.c.iii can't be triggered */
37339 goto found;
37340 }
37341
37342 /* track utf-8 non-continuation bytes */
37343 if ((p[0] & 0xc0) != 0x80) {
37344 match_start_coff++;
37345 }
37346 p++;
37347 }
37348
37349 not_found:
37350 /* not found */
37351 break;
37352
37353 found:
37354 matched = 1;
37355 match_start_boff = (duk_uint32_t) (p - p_start);
37356 match_end_coff = (duk_uint32_t) (match_start_coff + q_clen); /* constrained by string length */
37357 match_end_boff = (duk_uint32_t) (match_start_boff + q_blen); /* ditto */
37358
37359 /* empty match (may happen with empty separator) -> bump and continue */
37360 if (prev_match_end_boff == match_end_boff) {
37361 prev_match_end_boff++;
37362 prev_match_end_coff++;
37363 continue;
37364 }
37365 } /* if (is_regexp) */
37366
37367 /* stack[0] = separator (string or regexp)
37368 * stack[1] = limit
37369 * stack[2] = input string
37370 * stack[3] = result array
37371 * stack[4] = regexp res_obj (if is_regexp)
37372 */
37373
37374 DUK_DDD(DUK_DDDPRINT("split; match_start b=%ld,c=%ld, match_end b=%ld,c=%ld, prev_end b=%ld,c=%ld",
37375 (long) match_start_boff, (long) match_start_coff,
37376 (long) match_end_boff, (long) match_end_coff,
37377 (long) prev_match_end_boff, (long) prev_match_end_coff));
37378
37379 duk_push_lstring(ctx,
37380 (const char *) (DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff),
37381 (duk_size_t) (match_start_boff - prev_match_end_boff));
37382 duk_put_prop_index(ctx, 3, arr_idx);
37383 arr_idx++;
37384 if (arr_idx >= limit) {
37385 goto hit_limit;
37386 }
37387
37388#if defined(DUK_USE_REGEXP_SUPPORT)
37389 if (is_regexp) {
37390 duk_size_t i, len;
37391
37392 len = duk_get_length(ctx, 4);
37393 for (i = 1; i < len; i++) {
37394 DUK_ASSERT(i <= DUK_UARRIDX_MAX); /* cannot have >4G captures */
37395 duk_get_prop_index(ctx, 4, (duk_uarridx_t) i);
37396 duk_put_prop_index(ctx, 3, arr_idx);
37397 arr_idx++;
37398 if (arr_idx >= limit) {
37399 goto hit_limit;
37400 }
37401 }
37402
37403 duk_pop(ctx);
37404 /* lastIndex already set up for next match */
37405 } else {
37406#else /* DUK_USE_REGEXP_SUPPORT */
37407 { /* unconditionally */
37408#endif /* DUK_USE_REGEXP_SUPPORT */
37409 /* no action */
37410 }
37411
37412 prev_match_end_boff = match_end_boff;
37413 prev_match_end_coff = match_end_coff;
37414 continue;
37415 } /* for */
37416
37417 /* Combined step 11 (empty string special case) and 14-15. */
37418
37419 DUK_DDD(DUK_DDDPRINT("split trailer; prev_end b=%ld,c=%ld",
37420 (long) prev_match_end_boff, (long) prev_match_end_coff));
37421
37422 if (DUK_HSTRING_GET_CHARLEN(h_input) > 0 || !matched) {
37423 /* Add trailer if:
37424 * a) non-empty input
37425 * b) empty input and no (zero size) match found (step 11)
37426 */
37427
37428 duk_push_lstring(ctx,
37429 (const char *) DUK_HSTRING_GET_DATA(h_input) + prev_match_end_boff,
37430 (duk_size_t) (DUK_HSTRING_GET_BYTELEN(h_input) - prev_match_end_boff));
37431 duk_put_prop_index(ctx, 3, arr_idx);
37432 /* No arr_idx update or limit check */
37433 }
37434
37435 return 1;
37436
37437 hit_limit:
37438#if defined(DUK_USE_REGEXP_SUPPORT)
37439 if (is_regexp) {
37440 duk_pop(ctx);
37441 }
37442#endif
37443
37444 return 1;
37445}
37446
37447/*
37448 * Various
37449 */
37450
37451#if defined(DUK_USE_REGEXP_SUPPORT)
37452DUK_LOCAL void duk__to_regexp_helper(duk_context *ctx, duk_idx_t idx, duk_bool_t force_new) {
37453 duk_hobject *h;
37454
37455 /* Shared helper for match() steps 3-4, search() steps 3-4. */
37456
37457 DUK_ASSERT(idx >= 0);
37458
37459 if (force_new) {
37460 goto do_new;
37461 }
37462
37463 h = duk_get_hobject_with_class(ctx, idx, DUK_HOBJECT_CLASS_REGEXP);
37464 if (!h) {
37465 goto do_new;
37466 }
37467 return;
37468
37469 do_new:
37470 duk_push_hobject_bidx(ctx, DUK_BIDX_REGEXP_CONSTRUCTOR);
37471 duk_dup(ctx, idx);
37472 duk_new(ctx, 1); /* [ ... RegExp val ] -> [ ... res ] */
37473 duk_replace(ctx, idx);
37474}
37475#endif /* DUK_USE_REGEXP_SUPPORT */
37476
37477#if defined(DUK_USE_REGEXP_SUPPORT)
37478DUK_INTERNAL duk_ret_t duk_bi_string_prototype_search(duk_context *ctx) {
37479 duk_hthread *thr = (duk_hthread *) ctx;
37480
37481 /* Easiest way to implement the search required by the specification
37482 * is to do a RegExp test() with lastIndex forced to zero. To avoid
37483 * side effects on the argument, "clone" the RegExp if a RegExp was
37484 * given as input.
37485 *
37486 * The global flag of the RegExp should be ignored; setting lastIndex
37487 * to zero (which happens when "cloning" the RegExp) should have an
37488 * equivalent effect.
37489 */
37490
37491 DUK_ASSERT_TOP(ctx, 1);
37492 (void) duk_push_this_coercible_to_string(ctx); /* at index 1 */
37493 duk__to_regexp_helper(ctx, 0 /*index*/, 1 /*force_new*/);
37494
37495 /* stack[0] = regexp
37496 * stack[1] = string
37497 */
37498
37499 /* Avoid using RegExp.prototype methods, as they're writable and
37500 * configurable and may have been changed.
37501 */
37502
37503 duk_dup_0(ctx);
37504 duk_dup_1(ctx); /* [ ... re_obj input ] */
37505 duk_regexp_match(thr); /* -> [ ... res_obj ] */
37506
37507 if (!duk_is_object(ctx, -1)) {
37508 duk_push_int(ctx, -1);
37509 return 1;
37510 }
37511
37512 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INDEX);
37513 DUK_ASSERT(duk_is_number(ctx, -1));
37514 return 1;
37515}
37516#endif /* DUK_USE_REGEXP_SUPPORT */
37517
37518#if defined(DUK_USE_REGEXP_SUPPORT)
37519DUK_INTERNAL duk_ret_t duk_bi_string_prototype_match(duk_context *ctx) {
37520 duk_hthread *thr = (duk_hthread *) ctx;
37521 duk_bool_t global;
37522 duk_int_t prev_last_index;
37523 duk_int_t this_index;
37524 duk_int_t arr_idx;
37525
37526 DUK_ASSERT_TOP(ctx, 1);
37527 (void) duk_push_this_coercible_to_string(ctx);
37528 duk__to_regexp_helper(ctx, 0 /*index*/, 0 /*force_new*/);
37529 global = duk_get_prop_stridx_boolean(ctx, 0, DUK_STRIDX_GLOBAL, NULL);
37530 DUK_ASSERT_TOP(ctx, 2);
37531
37532 /* stack[0] = regexp
37533 * stack[1] = string
37534 */
37535
37536 if (!global) {
37537 duk_regexp_match(thr); /* -> [ res_obj ] */
37538 return 1; /* return 'res_obj' */
37539 }
37540
37541 /* Global case is more complex. */
37542
37543 /* [ regexp string ] */
37544
37545 duk_push_int(ctx, 0);
37546 duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_LAST_INDEX);
37547 duk_push_array(ctx);
37548
37549 /* [ regexp string res_arr ] */
37550
37551 prev_last_index = 0;
37552 arr_idx = 0;
37553
37554 for (;;) {
37555 DUK_ASSERT_TOP(ctx, 3);
37556
37557 duk_dup_0(ctx);
37558 duk_dup_1(ctx);
37559 duk_regexp_match(thr); /* -> [ ... regexp string ] -> [ ... res_obj ] */
37560
37561 if (!duk_is_object(ctx, -1)) {
37562 duk_pop(ctx);
37563 break;
37564 }
37565
37566 duk_get_prop_stridx_short(ctx, 0, DUK_STRIDX_LAST_INDEX);
37567 DUK_ASSERT(duk_is_number(ctx, -1));
37568 this_index = duk_get_int(ctx, -1);
37569 duk_pop(ctx);
37570
37571 if (this_index == prev_last_index) {
37572 this_index++;
37573 duk_push_int(ctx, this_index);
37574 duk_put_prop_stridx_short(ctx, 0, DUK_STRIDX_LAST_INDEX);
37575 }
37576 prev_last_index = this_index;
37577
37578 duk_get_prop_index(ctx, -1, 0); /* match string */
37579 duk_put_prop_index(ctx, 2, arr_idx);
37580 arr_idx++;
37581 duk_pop(ctx); /* res_obj */
37582 }
37583
37584 if (arr_idx == 0) {
37585 duk_push_null(ctx);
37586 }
37587
37588 return 1; /* return 'res_arr' or 'null' */
37589}
37590#endif /* DUK_USE_REGEXP_SUPPORT */
37591
37592DUK_INTERNAL duk_ret_t duk_bi_string_prototype_concat(duk_context *ctx) {
37593 /* duk_concat() coerces arguments with ToString() in correct order */
37594 (void) duk_push_this_coercible_to_string(ctx);
37595 duk_insert(ctx, 0); /* this is relatively expensive */
37596 duk_concat(ctx, duk_get_top(ctx));
37597 return 1;
37598}
37599
37600DUK_INTERNAL duk_ret_t duk_bi_string_prototype_trim(duk_context *ctx) {
37601 DUK_ASSERT_TOP(ctx, 0);
37602 (void) duk_push_this_coercible_to_string(ctx);
37603 duk_trim(ctx, 0);
37604 DUK_ASSERT_TOP(ctx, 1);
37605 return 1;
37606}
37607
37608#if defined(DUK_USE_ES6)
37609DUK_INTERNAL duk_ret_t duk_bi_string_prototype_repeat(duk_context *ctx) {
37610 duk_hstring *h_input;
37611 duk_size_t input_blen;
37612 duk_size_t result_len;
37613 duk_int_t count_signed;
37614 duk_uint_t count;
37615 const duk_uint8_t *src;
37616 duk_uint8_t *buf;
37617 duk_uint8_t *p;
37618 duk_double_t d;
37619#if !defined(DUK_USE_PREFER_SIZE)
37620 duk_size_t copy_size;
37621 duk_uint8_t *p_end;
37622#endif
37623
37624 DUK_ASSERT_TOP(ctx, 1);
37625 h_input = duk_push_this_coercible_to_string(ctx);
37626 DUK_ASSERT(h_input != NULL);
37627 input_blen = DUK_HSTRING_GET_BYTELEN(h_input);
37628
37629 /* Count is ToNumber() coerced; +Infinity must be always rejected
37630 * (even if input string is zero length), as well as negative values
37631 * and -Infinity. -Infinity doesn't require an explicit check
37632 * because duk_get_int() clamps it to DUK_INT_MIN which gets rejected
37633 * as a negative value (regardless of input string length).
37634 */
37635 d = duk_to_number(ctx, 0);
37636 if (duk_double_is_posinf(d)) {
37637 goto fail_range;
37638 }
37639 count_signed = duk_get_int(ctx, 0);
37640 if (count_signed < 0) {
37641 goto fail_range;
37642 }
37643 count = (duk_uint_t) count_signed;
37644
37645 /* Overflow check for result length. */
37646 result_len = count * input_blen;
37647 if (count != 0 && result_len / count != input_blen) {
37648 goto fail_range;
37649 }
37650
37651 /* Temporary fixed buffer, later converted to string. */
37652 buf = (duk_uint8_t *) duk_push_fixed_buffer_nozero(ctx, result_len);
37653 src = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
37654
37655#if defined(DUK_USE_PREFER_SIZE)
37656 p = buf;
37657 while (count-- > 0) {
37658 DUK_MEMCPY((void *) p, (const void *) src, input_blen); /* copy size may be zero */
37659 p += input_blen;
37660 }
37661#else /* DUK_USE_PREFER_SIZE */
37662 /* Take advantage of already copied pieces to speed up the process
37663 * especially for small repeated strings.
37664 */
37665 p = buf;
37666 p_end = p + result_len;
37667 copy_size = input_blen;
37668 for (;;) {
37669 duk_size_t remain = (duk_size_t) (p_end - p);
37670 DUK_DDD(DUK_DDDPRINT("remain=%ld, copy_size=%ld, input_blen=%ld, result_len=%ld",
37671 (long) remain, (long) copy_size, (long) input_blen,
37672 (long) result_len));
37673 if (remain <= copy_size) {
37674 /* If result_len is zero, this case is taken and does
37675 * a zero size copy.
37676 */
37677 DUK_MEMCPY((void *) p, (const void *) src, remain);
37678 break;
37679 } else {
37680 DUK_MEMCPY((void *) p, (const void *) src, copy_size);
37681 p += copy_size;
37682 copy_size *= 2;
37683 }
37684
37685 src = (const duk_uint8_t *) buf; /* Use buf as source for larger copies. */
37686 }
37687#endif /* DUK_USE_PREFER_SIZE */
37688
37689 /* XXX: It would be useful to be able to create a duk_hstring with
37690 * a certain byte size whose data area wasn't initialized and which
37691 * wasn't in the string table yet. This would allow a string to be
37692 * constructed directly without a buffer temporary and when it was
37693 * finished, it could be injected into the string table. Currently
37694 * this isn't possible because duk_hstrings are only tracked by the
37695 * intern table (they are not in heap_allocated).
37696 */
37697
37698 duk_buffer_to_string(ctx, -1); /* Safe if input is safe. */
37699 return 1;
37700
37701 fail_range:
37702 DUK_DCERROR_RANGE_INVALID_ARGS((duk_hthread *) ctx);
37703}
37704#endif /* DUK_USE_ES6 */
37705
37706DUK_INTERNAL duk_ret_t duk_bi_string_prototype_locale_compare(duk_context *ctx) {
37707 duk_hstring *h1;
37708 duk_hstring *h2;
37709 duk_size_t h1_len, h2_len, prefix_len;
37710 duk_small_int_t ret = 0;
37711 duk_small_int_t rc;
37712
37713 /* The current implementation of localeCompare() is simply a codepoint
37714 * by codepoint comparison, implemented with a simple string compare
37715 * because UTF-8 should preserve codepoint ordering (assuming valid
37716 * shortest UTF-8 encoding).
37717 *
37718 * The specification requires that the return value must be related
37719 * to the sort order: e.g. negative means that 'this' comes before
37720 * 'that' in sort order. We assume an ascending sort order.
37721 */
37722
37723 /* XXX: could share code with duk_js_ops.c, duk_js_compare_helper */
37724
37725 h1 = duk_push_this_coercible_to_string(ctx);
37726 DUK_ASSERT(h1 != NULL);
37727
37728 h2 = duk_to_hstring(ctx, 0);
37729 DUK_ASSERT(h2 != NULL);
37730
37731 h1_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1);
37732 h2_len = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2);
37733 prefix_len = (h1_len <= h2_len ? h1_len : h2_len);
37734
37735 /* Zero size compare not an issue with DUK_MEMCMP. */
37736 rc = (duk_small_int_t) DUK_MEMCMP((const void *) DUK_HSTRING_GET_DATA(h1),
37737 (const void *) DUK_HSTRING_GET_DATA(h2),
37738 (size_t) prefix_len);
37739
37740 if (rc < 0) {
37741 ret = -1;
37742 goto done;
37743 } else if (rc > 0) {
37744 ret = 1;
37745 goto done;
37746 }
37747
37748 /* prefix matches, lengths matter now */
37749 if (h1_len > h2_len) {
37750 ret = 1;
37751 goto done;
37752 } else if (h1_len == h2_len) {
37753 DUK_ASSERT(ret == 0);
37754 goto done;
37755 }
37756 ret = -1;
37757 goto done;
37758
37759 done:
37760 duk_push_int(ctx, (duk_int_t) ret);
37761 return 1;
37762}
37763
37764#endif /* DUK_USE_STRING_BUILTIN */
37765/*
37766 * Symbol built-in
37767 */
37768
37769/* #include duk_internal.h -> already included */
37770
37771#if defined(DUK_USE_SYMBOL_BUILTIN)
37772
37773/*
37774 * Constructor
37775 */
37776
37777DUK_INTERNAL duk_ret_t duk_bi_symbol_constructor_shared(duk_context *ctx) {
37778 duk_hthread *thr;
37779 const duk_uint8_t *desc;
37780 duk_size_t len;
37781 duk_uint8_t *buf;
37782 duk_uint8_t *p;
37783 duk_int_t magic;
37784
37785 thr = (duk_hthread *) ctx;
37786
37787 magic = duk_get_current_magic(ctx);
37788 if (duk_is_undefined(ctx, 0) && (magic == 0)) {
37789 /* Symbol() accepts undefined and empty string, but they are
37790 * treated differently.
37791 */
37792 desc = NULL;
37793 len = 0;
37794 } else {
37795 /* Symbol.for() coerces undefined to 'undefined' */
37796 desc = (const duk_uint8_t *) duk_to_lstring(ctx, 0, &len);
37797 }
37798
37799 /* Maximum symbol data length:
37800 * +1 initial byte (0x80 or 0x81)
37801 * +len description
37802 * +1 0xff after description, before unique suffix
37803 * +17 autogenerated unique suffix: 'ffffffff-ffffffff' is longest
37804 * +1 0xff after unique suffix for symbols with undefined description
37805 */
37806 buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, 1 + len + 1 + 17 + 1);
37807 p = buf + 1;
37808 DUK_ASSERT(desc != NULL || len == 0); /* may be NULL if len is 0 */
37809 DUK_MEMCPY((void *) p, (const void *) desc, len);
37810 p += len;
37811 if (magic == 0) {
37812 /* Symbol(): create unique symbol. Use two 32-bit values
37813 * to avoid dependency on 64-bit types and 64-bit integer
37814 * formatting (at least for now).
37815 */
37816 if (++thr->heap->sym_counter[0] == 0) {
37817 thr->heap->sym_counter[1]++;
37818 }
37819 p += DUK_SPRINTF((char *) p, "\xFF" "%lx-%lx",
37820 (unsigned long) thr->heap->sym_counter[1],
37821 (unsigned long) thr->heap->sym_counter[0]);
37822 if (desc == NULL) {
37823 /* Special case for 'undefined' description, trailing
37824 * 0xff distinguishes from empty string description,
37825 * but needs minimal special case handling elsewhere.
37826 */
37827 *p++ = 0xff;
37828 }
37829 buf[0] = 0x81;
37830 } else {
37831 /* Symbol.for(): create a global symbol */
37832 buf[0] = 0x80;
37833 }
37834
37835 duk_push_lstring(ctx, (const char *) buf, (duk_size_t) (p - buf));
37836 DUK_DDD(DUK_DDDPRINT("created symbol: %!T", duk_get_tval(ctx, -1)));
37837 return 1;
37838}
37839
37840DUK_LOCAL duk_hstring *duk__auto_unbox_symbol(duk_context *ctx, duk_tval *tv_arg) {
37841 duk_tval *tv;
37842 duk_tval tv_val;
37843 duk_hobject *h_obj;
37844 duk_hstring *h_str;
37845
37846 DUK_ASSERT(tv_arg != NULL);
37847
37848 /* XXX: add internal helper: duk_auto_unbox_tval(ctx, tv, mask); */
37849 /* XXX: add internal helper: duk_auto_unbox(ctx, tv, idx); */
37850
37851 tv = tv_arg;
37852 if (DUK_TVAL_IS_OBJECT(tv)) {
37853 h_obj = DUK_TVAL_GET_OBJECT(tv);
37854 DUK_ASSERT(h_obj != NULL);
37855 if (DUK_HOBJECT_GET_CLASS_NUMBER(h_obj) == DUK_HOBJECT_CLASS_SYMBOL) {
37856 if (!duk_hobject_get_internal_value(((duk_hthread *) ctx)->heap, h_obj, &tv_val)) {
37857 return NULL;
37858 }
37859 tv = &tv_val;
37860 } else {
37861 return NULL;
37862 }
37863 }
37864
37865 if (!DUK_TVAL_IS_STRING(tv)) {
37866 return NULL;
37867 }
37868 h_str = DUK_TVAL_GET_STRING(tv);
37869 DUK_ASSERT(h_str != NULL);
37870
37871 if (!DUK_HSTRING_HAS_SYMBOL(h_str)) {
37872 return NULL;
37873 }
37874
37875 return h_str;
37876}
37877
37878DUK_INTERNAL duk_ret_t duk_bi_symbol_tostring_shared(duk_context *ctx) {
37879 duk_hstring *h_str;
37880
37881 h_str = duk__auto_unbox_symbol(ctx, DUK_HTHREAD_THIS_PTR((duk_hthread *) ctx));
37882 if (h_str == NULL) {
37883 return DUK_RET_TYPE_ERROR;
37884 }
37885
37886 if (duk_get_current_magic(ctx) == 0) {
37887 /* .toString() */
37888 duk_push_symbol_descriptive_string(ctx, h_str);
37889 } else {
37890 /* .valueOf() */
37891 }
37892 return 1;
37893}
37894
37895DUK_INTERNAL duk_ret_t duk_bi_symbol_key_for(duk_context *ctx) {
37896 duk_hstring *h;
37897 const duk_uint8_t *p;
37898
37899 /* Argument must be a symbol but not checked here. The initial byte
37900 * check will catch non-symbol strings.
37901 */
37902 h = duk_require_hstring(ctx, 0);
37903 DUK_ASSERT(h != NULL);
37904
37905 p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
37906 DUK_ASSERT(p != NULL);
37907
37908 /* Even for zero length strings there's at least one NUL byte so
37909 * we can safely check the initial byte.
37910 */
37911 if (p[0] == 0x80) {
37912 /* Global symbol, return its key (bytes just after the initial byte). */
37913 duk_push_lstring(ctx, (const char *) (p + 1), DUK_HSTRING_GET_BYTELEN(h) - 1);
37914 return 1;
37915 } else if (p[0] == 0x81 || p[0] == 0xff) {
37916 /* Local symbol or hidden symbol, return undefined. */
37917 return 0;
37918 }
37919
37920 /* Covers normal strings and unknown initial bytes. */
37921 return DUK_RET_TYPE_ERROR;
37922}
37923
37924DUK_INTERNAL duk_ret_t duk_bi_symbol_toprimitive(duk_context *ctx) {
37925 duk_hstring *h_str;
37926
37927 h_str = duk__auto_unbox_symbol(ctx, DUK_HTHREAD_THIS_PTR((duk_hthread *) ctx));
37928 if (h_str == NULL) {
37929 return DUK_RET_TYPE_ERROR;
37930 }
37931 duk_push_hstring(ctx, h_str);
37932 return 1;
37933}
37934
37935#endif /* DUK_USE_SYMBOL_BUILTIN */
37936/*
37937 * Thread builtins
37938 */
37939
37940/* #include duk_internal.h -> already included */
37941
37942/*
37943 * Constructor
37944 */
37945
37946#if defined(DUK_USE_COROUTINE_SUPPORT)
37947DUK_INTERNAL duk_ret_t duk_bi_thread_constructor(duk_context *ctx) {
37948 duk_hthread *new_thr;
37949 duk_hobject *func;
37950
37951 /* Check that the argument is callable; this is not 100% because we
37952 * don't allow native functions to be a thread's initial function.
37953 * Resume will reject such functions in any case.
37954 */
37955 /* XXX: need a duk_require_func_promote_lfunc() */
37956 func = duk_require_hobject_promote_lfunc(ctx, 0);
37957 DUK_ASSERT(func != NULL);
37958 duk_require_callable(ctx, 0);
37959
37960 duk_push_thread(ctx);
37961 new_thr = (duk_hthread *) duk_known_hobject(ctx, -1);
37962 new_thr->state = DUK_HTHREAD_STATE_INACTIVE;
37963
37964 /* push initial function call to new thread stack; this is
37965 * picked up by resume().
37966 */
37967 duk_push_hobject((duk_context *) new_thr, func);
37968
37969 return 1; /* return thread */
37970}
37971#endif
37972
37973/*
37974 * Resume a thread.
37975 *
37976 * The thread must be in resumable state, either (a) new thread which hasn't
37977 * yet started, or (b) a thread which has previously yielded. This method
37978 * must be called from an Ecmascript function.
37979 *
37980 * Args:
37981 * - thread
37982 * - value
37983 * - isError (defaults to false)
37984 *
37985 * Note: yield and resume handling is currently asymmetric.
37986 */
37987
37988#if defined(DUK_USE_COROUTINE_SUPPORT)
37989DUK_INTERNAL duk_ret_t duk_bi_thread_resume(duk_context *ctx) {
37990 duk_hthread *thr = (duk_hthread *) ctx;
37991 duk_hthread *thr_resume;
37992 duk_hobject *caller_func;
37993 duk_small_int_t is_error;
37994
37995 DUK_DDD(DUK_DDDPRINT("Duktape.Thread.resume(): thread=%!T, value=%!T, is_error=%!T",
37996 (duk_tval *) duk_get_tval(ctx, 0),
37997 (duk_tval *) duk_get_tval(ctx, 1),
37998 (duk_tval *) duk_get_tval(ctx, 2)));
37999
38000 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
38001 DUK_ASSERT(thr->heap->curr_thread == thr);
38002
38003 thr_resume = duk_require_hthread(ctx, 0);
38004 is_error = (duk_small_int_t) duk_to_boolean(ctx, 2);
38005 duk_set_top(ctx, 2);
38006
38007 /* [ thread value ] */
38008
38009 /*
38010 * Thread state and calling context checks
38011 */
38012
38013 if (thr->callstack_top < 2) {
38014 DUK_DD(DUK_DDPRINT("resume state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.resume)"));
38015 goto state_error;
38016 }
38017 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); /* us */
38018 DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)));
38019 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL); /* caller */
38020
38021 caller_func = DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2);
38022 if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) {
38023 DUK_DD(DUK_DDPRINT("resume state invalid: caller must be Ecmascript code"));
38024 goto state_error;
38025 }
38026
38027 /* Note: there is no requirement that: 'thr->callstack_preventcount == 1'
38028 * like for yield.
38029 */
38030
38031 if (thr_resume->state != DUK_HTHREAD_STATE_INACTIVE &&
38032 thr_resume->state != DUK_HTHREAD_STATE_YIELDED) {
38033 DUK_DD(DUK_DDPRINT("resume state invalid: target thread must be INACTIVE or YIELDED"));
38034 goto state_error;
38035 }
38036
38037 DUK_ASSERT(thr_resume->state == DUK_HTHREAD_STATE_INACTIVE ||
38038 thr_resume->state == DUK_HTHREAD_STATE_YIELDED);
38039
38040 /* Further state-dependent pre-checks */
38041
38042 if (thr_resume->state == DUK_HTHREAD_STATE_YIELDED) {
38043 /* no pre-checks now, assume a previous yield() has left things in
38044 * tip-top shape (longjmp handler will assert for these).
38045 */
38046 } else {
38047 duk_hobject *h_fun;
38048
38049 DUK_ASSERT(thr_resume->state == DUK_HTHREAD_STATE_INACTIVE);
38050
38051 /* The initial function must be an Ecmascript function (but
38052 * can be bound). We must make sure of that before we longjmp
38053 * because an error in the RESUME handler call processing will
38054 * not be handled very cleanly.
38055 */
38056 if ((thr_resume->callstack_top != 0) ||
38057 (thr_resume->valstack_top - thr_resume->valstack != 1)) {
38058 goto state_error;
38059 }
38060
38061 duk_push_tval(ctx, DUK_GET_TVAL_NEGIDX((duk_context *) thr_resume, -1));
38062 duk_resolve_nonbound_function(ctx);
38063 h_fun = duk_require_hobject(ctx, -1); /* reject lightfuncs on purpose */
38064 if (!DUK_HOBJECT_IS_CALLABLE(h_fun) || !DUK_HOBJECT_IS_COMPFUNC(h_fun)) {
38065 goto state_error;
38066 }
38067 duk_pop(ctx);
38068 }
38069
38070 /*
38071 * The error object has been augmented with a traceback and other
38072 * info from its creation point -- usually another thread. The
38073 * error handler is called here right before throwing, but it also
38074 * runs in the resumer's thread. It might be nice to get a traceback
38075 * from the resumee but this is not the case now.
38076 */
38077
38078#if defined(DUK_USE_AUGMENT_ERROR_THROW)
38079 if (is_error) {
38080 DUK_ASSERT_TOP(ctx, 2); /* value (error) is at stack top */
38081 duk_err_augment_error_throw(thr); /* in resumer's context */
38082 }
38083#endif
38084
38085#if defined(DUK_USE_DEBUG)
38086 if (is_error) {
38087 DUK_DDD(DUK_DDDPRINT("RESUME ERROR: thread=%!T, value=%!T",
38088 (duk_tval *) duk_get_tval(ctx, 0),
38089 (duk_tval *) duk_get_tval(ctx, 1)));
38090 } else if (thr_resume->state == DUK_HTHREAD_STATE_YIELDED) {
38091 DUK_DDD(DUK_DDDPRINT("RESUME NORMAL: thread=%!T, value=%!T",
38092 (duk_tval *) duk_get_tval(ctx, 0),
38093 (duk_tval *) duk_get_tval(ctx, 1)));
38094 } else {
38095 DUK_DDD(DUK_DDDPRINT("RESUME INITIAL: thread=%!T, value=%!T",
38096 (duk_tval *) duk_get_tval(ctx, 0),
38097 (duk_tval *) duk_get_tval(ctx, 1)));
38098 }
38099#endif
38100
38101 thr->heap->lj.type = DUK_LJ_TYPE_RESUME;
38102
38103 /* lj value2: thread */
38104 DUK_ASSERT(thr->valstack_bottom < thr->valstack_top);
38105 DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value2, &thr->valstack_bottom[0]); /* side effects */
38106
38107 /* lj value1: value */
38108 DUK_ASSERT(thr->valstack_bottom + 1 < thr->valstack_top);
38109 DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[1]); /* side effects */
38110 DUK_TVAL_CHKFAST_INPLACE_SLOW(&thr->heap->lj.value1);
38111
38112 thr->heap->lj.iserror = is_error;
38113
38114 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* call is from executor, so we know we have a jmpbuf */
38115 duk_err_longjmp(thr); /* execution resumes in bytecode executor */
38116 DUK_UNREACHABLE();
38117 /* Never here, fall through to error (from compiler point of view). */
38118
38119 state_error:
38120 DUK_DCERROR_TYPE_INVALID_STATE(thr);
38121}
38122#endif
38123
38124/*
38125 * Yield the current thread.
38126 *
38127 * The thread must be in yieldable state: it must have a resumer, and there
38128 * must not be any yield-preventing calls (native calls and constructor calls,
38129 * currently) in the thread's call stack (otherwise a resume would not be
38130 * possible later). This method must be called from an Ecmascript function.
38131 *
38132 * Args:
38133 * - value
38134 * - isError (defaults to false)
38135 *
38136 * Note: yield and resume handling is currently asymmetric.
38137 */
38138
38139#if defined(DUK_USE_COROUTINE_SUPPORT)
38140DUK_INTERNAL duk_ret_t duk_bi_thread_yield(duk_context *ctx) {
38141 duk_hthread *thr = (duk_hthread *) ctx;
38142 duk_hobject *caller_func;
38143 duk_small_int_t is_error;
38144
38145 DUK_DDD(DUK_DDDPRINT("Duktape.Thread.yield(): value=%!T, is_error=%!T",
38146 (duk_tval *) duk_get_tval(ctx, 0),
38147 (duk_tval *) duk_get_tval(ctx, 1)));
38148
38149 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
38150 DUK_ASSERT(thr->heap->curr_thread == thr);
38151
38152 is_error = (duk_small_int_t) duk_to_boolean(ctx, 1);
38153 duk_set_top(ctx, 1);
38154
38155 /* [ value ] */
38156
38157 /*
38158 * Thread state and calling context checks
38159 */
38160
38161 if (!thr->resumer) {
38162 DUK_DD(DUK_DDPRINT("yield state invalid: current thread must have a resumer"));
38163 goto state_error;
38164 }
38165 DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED);
38166
38167 if (thr->callstack_top < 2) {
38168 DUK_DD(DUK_DDPRINT("yield state invalid: callstack should contain at least 2 entries (caller and Duktape.Thread.yield)"));
38169 goto state_error;
38170 }
38171 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL); /* us */
38172 DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)));
38173 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL); /* caller */
38174
38175 caller_func = DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2);
38176 if (!DUK_HOBJECT_IS_COMPFUNC(caller_func)) {
38177 DUK_DD(DUK_DDPRINT("yield state invalid: caller must be Ecmascript code"));
38178 goto state_error;
38179 }
38180
38181 DUK_ASSERT(thr->callstack_preventcount >= 1); /* should never be zero, because we (Duktape.Thread.yield) are on the stack */
38182 if (thr->callstack_preventcount != 1) {
38183 /* Note: the only yield-preventing call is Duktape.Thread.yield(), hence check for 1, not 0 */
38184 DUK_DD(DUK_DDPRINT("yield state invalid: there must be no yield-preventing calls in current thread callstack (preventcount is %ld)",
38185 (long) thr->callstack_preventcount));
38186 goto state_error;
38187 }
38188
38189 /*
38190 * The error object has been augmented with a traceback and other
38191 * info from its creation point -- usually the current thread.
38192 * The error handler, however, is called right before throwing
38193 * and runs in the yielder's thread.
38194 */
38195
38196#if defined(DUK_USE_AUGMENT_ERROR_THROW)
38197 if (is_error) {
38198 DUK_ASSERT_TOP(ctx, 1); /* value (error) is at stack top */
38199 duk_err_augment_error_throw(thr); /* in yielder's context */
38200 }
38201#endif
38202
38203#if defined(DUK_USE_DEBUG)
38204 if (is_error) {
38205 DUK_DDD(DUK_DDDPRINT("YIELD ERROR: value=%!T",
38206 (duk_tval *) duk_get_tval(ctx, 0)));
38207 } else {
38208 DUK_DDD(DUK_DDDPRINT("YIELD NORMAL: value=%!T",
38209 (duk_tval *) duk_get_tval(ctx, 0)));
38210 }
38211#endif
38212
38213 /*
38214 * Process yield
38215 *
38216 * After longjmp(), processing continues in bytecode executor longjmp
38217 * handler, which will e.g. update thr->resumer to NULL.
38218 */
38219
38220 thr->heap->lj.type = DUK_LJ_TYPE_YIELD;
38221
38222 /* lj value1: value */
38223 DUK_ASSERT(thr->valstack_bottom < thr->valstack_top);
38224 DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, &thr->valstack_bottom[0]); /* side effects */
38225 DUK_TVAL_CHKFAST_INPLACE_SLOW(&thr->heap->lj.value1);
38226
38227 thr->heap->lj.iserror = is_error;
38228
38229 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* call is from executor, so we know we have a jmpbuf */
38230 duk_err_longjmp(thr); /* execution resumes in bytecode executor */
38231 DUK_UNREACHABLE();
38232 /* Never here, fall through to error (from compiler point of view). */
38233
38234 state_error:
38235 DUK_DCERROR_TYPE_INVALID_STATE(thr);
38236}
38237#endif
38238
38239#if defined(DUK_USE_COROUTINE_SUPPORT)
38240DUK_INTERNAL duk_ret_t duk_bi_thread_current(duk_context *ctx) {
38241 duk_push_current_thread(ctx);
38242 return 1;
38243}
38244#endif
38245/*
38246 * Type error thrower, E5 Section 13.2.3.
38247 */
38248
38249/* #include duk_internal.h -> already included */
38250
38251DUK_INTERNAL duk_ret_t duk_bi_type_error_thrower(duk_context *ctx) {
38252 DUK_DCERROR_TYPE_INVALID_ARGS((duk_hthread *) ctx);
38253}
38254/*
38255 * Fixed buffer helper useful for debugging, requires no allocation
38256 * which is critical for debugging.
38257 */
38258
38259/* #include duk_internal.h -> already included */
38260
38261#if defined(DUK_USE_DEBUG)
38262
38263DUK_INTERNAL void duk_fb_put_bytes(duk_fixedbuffer *fb, const duk_uint8_t *buffer, duk_size_t length) {
38264 duk_size_t avail;
38265 duk_size_t copylen;
38266
38267 avail = (fb->offset >= fb->length ? (duk_size_t) 0 : (duk_size_t) (fb->length - fb->offset));
38268 if (length > avail) {
38269 copylen = avail;
38270 fb->truncated = 1;
38271 } else {
38272 copylen = length;
38273 }
38274 DUK_MEMCPY(fb->buffer + fb->offset, buffer, copylen);
38275 fb->offset += copylen;
38276}
38277
38278DUK_INTERNAL void duk_fb_put_byte(duk_fixedbuffer *fb, duk_uint8_t x) {
38279 duk_fb_put_bytes(fb, (const duk_uint8_t *) &x, 1);
38280}
38281
38282DUK_INTERNAL void duk_fb_put_cstring(duk_fixedbuffer *fb, const char *x) {
38283 duk_fb_put_bytes(fb, (const duk_uint8_t *) x, (duk_size_t) DUK_STRLEN(x));
38284}
38285
38286DUK_INTERNAL void duk_fb_sprintf(duk_fixedbuffer *fb, const char *fmt, ...) {
38287 duk_size_t avail;
38288 va_list ap;
38289
38290 va_start(ap, fmt);
38291 avail = (fb->offset >= fb->length ? (duk_size_t) 0 : (duk_size_t) (fb->length - fb->offset));
38292 if (avail > 0) {
38293 duk_int_t res = (duk_int_t) DUK_VSNPRINTF((char *) (fb->buffer + fb->offset), avail, fmt, ap);
38294 if (res < 0) {
38295 /* error */
38296 } else if ((duk_size_t) res >= avail) {
38297 /* (maybe) truncated */
38298 fb->offset += avail;
38299 if ((duk_size_t) res > avail) {
38300 /* actual chars dropped (not just NUL term) */
38301 fb->truncated = 1;
38302 }
38303 } else {
38304 /* normal */
38305 fb->offset += res;
38306 }
38307 }
38308 va_end(ap);
38309}
38310
38311DUK_INTERNAL void duk_fb_put_funcptr(duk_fixedbuffer *fb, duk_uint8_t *fptr, duk_size_t fptr_size) {
38312 char buf[64+1];
38313 duk_debug_format_funcptr(buf, sizeof(buf), fptr, fptr_size);
38314 buf[sizeof(buf) - 1] = (char) 0;
38315 duk_fb_put_cstring(fb, buf);
38316}
38317
38318DUK_INTERNAL duk_bool_t duk_fb_is_full(duk_fixedbuffer *fb) {
38319 return (fb->offset >= fb->length);
38320}
38321
38322#endif /* DUK_USE_DEBUG */
38323/*
38324 * Custom formatter for debug printing, allowing Duktape specific data
38325 * structures (such as tagged values and heap objects) to be printed with
38326 * a nice format string. Because debug printing should not affect execution
38327 * state, formatting here must be independent of execution (see implications
38328 * below) and must not allocate memory.
38329 *
38330 * Custom format tags begin with a '%!' to safely distinguish them from
38331 * standard format tags. The following conversions are supported:
38332 *
38333 * %!T tagged value (duk_tval *)
38334 * %!O heap object (duk_heaphdr *)
38335 * %!I decoded bytecode instruction
38336 * %!C bytecode instruction opcode name (arg is long)
38337 *
38338 * Everything is serialized in a JSON-like manner. The default depth is one
38339 * level, internal prototype is not followed, and internal properties are not
38340 * serialized. The following modifiers change this behavior:
38341 *
38342 * @ print pointers
38343 * # print binary representations (where applicable)
38344 * d deep traversal of own properties (not prototype)
38345 * p follow prototype chain (useless without 'd')
38346 * i include internal properties (other than prototype)
38347 * x hexdump buffers
38348 * h heavy formatting
38349 *
38350 * For instance, the following serializes objects recursively, but does not
38351 * follow the prototype chain nor print internal properties: "%!dO".
38352 *
38353 * Notes:
38354 *
38355 * * Standard snprintf return value semantics seem to vary. This
38356 * implementation returns the number of bytes it actually wrote
38357 * (excluding the null terminator). If retval == buffer size,
38358 * output was truncated (except for corner cases).
38359 *
38360 * * Output format is intentionally different from Ecmascript
38361 * formatting requirements, as formatting here serves debugging
38362 * of internals.
38363 *
38364 * * Depth checking (and updating) is done in each type printer
38365 * separately, to allow them to call each other freely.
38366 *
38367 * * Some pathological structures might take ages to print (e.g.
38368 * self recursion with 100 properties pointing to the object
38369 * itself). To guard against these, each printer also checks
38370 * whether the output buffer is full; if so, early exit.
38371 *
38372 * * Reference loops are detected using a loop stack.
38373 */
38374
38375/* #include duk_internal.h -> already included */
38376
38377#if defined(DUK_USE_DEBUG)
38378
38379/* #include stdio.h -> already included */
38380/* #include stdarg.h -> already included */
38381#include <string.h>
38382
38383/* list of conversion specifiers that terminate a format tag;
38384 * this is unfortunately guesswork.
38385 */
38386#define DUK__ALLOWED_STANDARD_SPECIFIERS "diouxXeEfFgGaAcsCSpnm"
38387
38388/* maximum length of standard format tag that we support */
38389#define DUK__MAX_FORMAT_TAG_LENGTH 32
38390
38391/* heapobj recursion depth when deep printing is selected */
38392#define DUK__DEEP_DEPTH_LIMIT 8
38393
38394/* maximum recursion depth for loop detection stacks */
38395#define DUK__LOOP_STACK_DEPTH 256
38396
38397/* must match bytecode defines now; build autogenerate? */
38398DUK_LOCAL const char *duk__bc_optab[256] = {
38399 "LDREG", "STREG", "LDCONST", "LDINT", "LDINTX", "LDTHIS", "LDUNDEF", "LDNULL",
38400 "LDTRUE", "LDFALSE", "BNOT", "LNOT", "UNM", "UNP", "TYPEOF", "TYPEOFID",
38401 "EQ_RR", "EQ_CR", "EQ_RC", "EQ_CC", "NEQ_RR", "NEQ_CR", "NEQ_RC", "NEQ_CC",
38402 "SEQ_RR", "SEQ_CR", "SEQ_RC", "SEQ_CC", "SNEQ_RR", "SNEQ_CR", "SNEQ_RC", "SNEQ_CC",
38403
38404 "GT_RR", "GT_CR", "GT_RC", "GT_CC", "GE_RR", "GE_CR", "GE_RC", "GE_CC",
38405 "LT_RR", "LT_CR", "LT_RC", "LT_CC", "LE_RR", "LE_CR", "LE_RC", "LE_CC",
38406 "IFTRUE_R", "IFTRUE_C", "IFFALSE_R", "IFFALSE_C", "ADD_RR", "ADD_CR", "ADD_RC", "ADD_CC",
38407 "SUB_RR", "SUB_CR", "SUB_RC", "SUB_CC", "MUL_RR", "MUL_CR", "MUL_RC", "MUL_CC",
38408
38409 "DIV_RR", "DIV_CR", "DIV_RC", "DIV_CC", "MOD_RR", "MOD_CR", "MOD_RC", "MOD_CC",
38410 "BAND_RR", "BAND_CR", "BAND_RC", "BAND_CC", "BOR_RR", "BOR_CR", "BOR_RC", "BOR_CC",
38411 "BXOR_RR", "BXOR_CR", "BXOR_RC", "BXOR_CC", "BASL_RR", "BASL_CR", "BASL_RC", "BASL_CC",
38412 "BLSR_RR", "BLSR_CR", "BLSR_RC", "BLSR_CC", "BASR_RR", "BASR_CR", "BASR_RC", "BASR_CC",
38413
38414 "INSTOF_RR", "INSTOF_CR", "INSTOF_RC", "INSTOF_CC", "IN_RR", "IN_CR", "IN_RC", "IN_CC",
38415 "PREINCR", "PREDECR", "POSTINCR", "POSTDECR", "PREINCV", "PREDECV", "POSTINCV", "POSTDECV",
38416 "PREINCP_RR", "PREINCP_CR", "PREINCP_RC", "PREINCP_CC", "PREDECP_RR", "PREDECP_CR", "PREDECP_RC", "PREDECP_CC",
38417 "POSTINCP_RR", "POSTINCP_CR", "POSTINCP_RC", "POSTINCP_CC", "POSTDECP_RR", "POSTDECP_CR", "POSTDECP_RC", "POSTDECP_CC",
38418
38419 "GETPROP_RR", "GETPROP_CR", "GETPROP_RC", "GETPROP_CC", "PUTPROP_RR", "PUTPROP_CR", "PUTPROP_RC", "PUTPROP_CC",
38420 "DELPROP_RR", "DELPROP_CR", "DELPROP_RC", "DELPROP_CC", "DECLVAR_RR", "DECLVAR_CR", "DECLVAR_RC", "DECLVAR_CC",
38421 "REGEXP_RR", "REGEXP_RC", "REGEXP_CR", "REGEXP_CC", "CSVAR_RR", "CSVAR_CR", "CSVAR_RC", "CSVAR_CC",
38422 "CLOSURE", "GETVAR", "PUTVAR", "DELVAR", "JUMP", "RETREG", "RETUNDEF", "RETCONST",
38423
38424 "RETCONSTN", "LABEL", "ENDLABEL", "BREAK", "CONTINUE", "TRYCATCH", "ENDTRY", "ENDCATCH",
38425 "ENDFIN", "THROW", "CSREG", "EVALCALL", "CALL", "TAILCALL", "NEW", "NEWOBJ",
38426 "NEWARR", "MPUTOBJ", "MPUTOBJI", "INITSET", "INITGET", "MPUTARR", "MPUTARRI", "SETALEN",
38427 "INITENUM", "NEXTENUM", "INVLHS", "DEBUGGER", "NOP", "INVALID", "UNUSED190", "UNUSED191",
38428
38429 "UNUSED192", "UNUSED193", "UNUSED194", "UNUSED195", "UNUSED196", "UNUSED197", "UNUSED198", "UNUSED199",
38430 "UNUSED200", "UNUSED201", "UNUSED202", "UNUSED203", "UNUSED204", "UNUSED205", "UNUSED206", "UNUSED207",
38431 "UNUSED208", "UNUSED209", "UNUSED210", "UNUSED211", "UNUSED212", "UNUSED213", "UNUSED214", "UNUSED215",
38432 "UNUSED216", "UNUSED217", "UNUSED218", "UNUSED219", "UNUSED220", "UNUSED221", "UNUSED222", "UNUSED223",
38433
38434 "UNUSED224", "UNUSED225", "UNUSED226", "UNUSED227", "UNUSED228", "UNUSED229", "UNUSED230", "UNUSED231",
38435 "UNUSED232", "UNUSED233", "UNUSED234", "UNUSED235", "UNUSED236", "UNUSED237", "UNUSED238", "UNUSED239",
38436 "UNUSED240", "UNUSED241", "UNUSED242", "UNUSED243", "UNUSED244", "UNUSED245", "UNUSED246", "UNUSED247",
38437 "UNUSED248", "UNUSED249", "UNUSED250", "UNUSED251", "UNUSED252", "UNUSED253", "UNUSED254", "UNUSED255"
38438};
38439
38440typedef struct duk__dprint_state duk__dprint_state;
38441struct duk__dprint_state {
38442 duk_fixedbuffer *fb;
38443
38444 /* loop_stack_index could be perhaps be replaced by 'depth', but it's nice
38445 * to not couple these two mechanisms unnecessarily.
38446 */
38447 duk_hobject *loop_stack[DUK__LOOP_STACK_DEPTH];
38448 duk_int_t loop_stack_index;
38449 duk_int_t loop_stack_limit;
38450
38451 duk_int_t depth;
38452 duk_int_t depth_limit;
38453
38454 duk_bool_t pointer;
38455 duk_bool_t heavy;
38456 duk_bool_t binary;
38457 duk_bool_t follow_proto;
38458 duk_bool_t internal;
38459 duk_bool_t hexdump;
38460};
38461
38462/* helpers */
38463DUK_LOCAL_DECL void duk__print_hstring(duk__dprint_state *st, duk_hstring *k, duk_bool_t quotes);
38464DUK_LOCAL_DECL void duk__print_hobject(duk__dprint_state *st, duk_hobject *h);
38465DUK_LOCAL_DECL void duk__print_hbuffer(duk__dprint_state *st, duk_hbuffer *h);
38466DUK_LOCAL_DECL void duk__print_tval(duk__dprint_state *st, duk_tval *tv);
38467DUK_LOCAL_DECL void duk__print_instr(duk__dprint_state *st, duk_instr_t ins);
38468DUK_LOCAL_DECL void duk__print_heaphdr(duk__dprint_state *st, duk_heaphdr *h);
38469DUK_LOCAL_DECL void duk__print_shared_heaphdr(duk__dprint_state *st, duk_heaphdr *h);
38470DUK_LOCAL_DECL void duk__print_shared_heaphdr_string(duk__dprint_state *st, duk_heaphdr_string *h);
38471
38472DUK_LOCAL void duk__print_shared_heaphdr(duk__dprint_state *st, duk_heaphdr *h) {
38473 duk_fixedbuffer *fb = st->fb;
38474
38475 if (st->heavy) {
38476 duk_fb_sprintf(fb, "(%p)", (void *) h);
38477 }
38478
38479 if (!h) {
38480 return;
38481 }
38482
38483 if (st->binary) {
38484 duk_size_t i;
38485 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LBRACKET);
38486 for (i = 0; i < (duk_size_t) sizeof(*h); i++) {
38487 duk_fb_sprintf(fb, "%02lx", (unsigned long) ((duk_uint8_t *)h)[i]);
38488 }
38489 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RBRACKET);
38490 }
38491
38492#if defined(DUK_USE_REFERENCE_COUNTING) /* currently implicitly also DUK_USE_DOUBLE_LINKED_HEAP */
38493 if (st->heavy) {
38494 duk_fb_sprintf(fb, "[h_next=%p,h_prev=%p,h_refcount=%lu,h_flags=%08lx,type=%ld,"
38495 "reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]",
38496 (void *) DUK_HEAPHDR_GET_NEXT(NULL, h),
38497 (void *) DUK_HEAPHDR_GET_PREV(NULL, h),
38498 (unsigned long) DUK_HEAPHDR_GET_REFCOUNT(h),
38499 (unsigned long) DUK_HEAPHDR_GET_FLAGS(h),
38500 (long) DUK_HEAPHDR_GET_TYPE(h),
38501 (long) (DUK_HEAPHDR_HAS_REACHABLE(h) ? 1 : 0),
38502 (long) (DUK_HEAPHDR_HAS_TEMPROOT(h) ? 1 : 0),
38503 (long) (DUK_HEAPHDR_HAS_FINALIZABLE(h) ? 1 : 0),
38504 (long) (DUK_HEAPHDR_HAS_FINALIZED(h) ? 1 : 0));
38505 }
38506#else
38507 if (st->heavy) {
38508 duk_fb_sprintf(fb, "[h_next=%p,h_flags=%08lx,type=%ld,reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]",
38509 (void *) DUK_HEAPHDR_GET_NEXT(NULL, h),
38510 (unsigned long) DUK_HEAPHDR_GET_FLAGS(h),
38511 (long) DUK_HEAPHDR_GET_TYPE(h),
38512 (long) (DUK_HEAPHDR_HAS_REACHABLE(h) ? 1 : 0),
38513 (long) (DUK_HEAPHDR_HAS_TEMPROOT(h) ? 1 : 0),
38514 (long) (DUK_HEAPHDR_HAS_FINALIZABLE(h) ? 1 : 0),
38515 (long) (DUK_HEAPHDR_HAS_FINALIZED(h) ? 1 : 0));
38516 }
38517#endif
38518}
38519
38520DUK_LOCAL void duk__print_shared_heaphdr_string(duk__dprint_state *st, duk_heaphdr_string *h) {
38521 duk_fixedbuffer *fb = st->fb;
38522
38523 if (st->heavy) {
38524 duk_fb_sprintf(fb, "(%p)", (void *) h);
38525 }
38526
38527 if (!h) {
38528 return;
38529 }
38530
38531 if (st->binary) {
38532 duk_size_t i;
38533 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LBRACKET);
38534 for (i = 0; i < (duk_size_t) sizeof(*h); i++) {
38535 duk_fb_sprintf(fb, "%02lx", (unsigned long) ((duk_uint8_t *)h)[i]);
38536 }
38537 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RBRACKET);
38538 }
38539
38540#if defined(DUK_USE_REFERENCE_COUNTING)
38541 if (st->heavy) {
38542 duk_fb_sprintf(fb, "[h_refcount=%lu,h_flags=%08lx,type=%ld,reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]",
38543 (unsigned long) DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h),
38544 (unsigned long) DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) h),
38545 (long) DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h),
38546 (long) (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h) ? 1 : 0),
38547 (long) (DUK_HEAPHDR_HAS_TEMPROOT((duk_heaphdr *) h) ? 1 : 0),
38548 (long) (DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) h) ? 1 : 0),
38549 (long) (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h) ? 1 : 0));
38550 }
38551#else
38552 if (st->heavy) {
38553 duk_fb_sprintf(fb, "[h_flags=%08lx,type=%ld,reachable=%ld,temproot=%ld,finalizable=%ld,finalized=%ld]",
38554 (unsigned long) DUK_HEAPHDR_GET_FLAGS((duk_heaphdr *) h),
38555 (long) DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h),
38556 (long) (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h) ? 1 : 0),
38557 (long) (DUK_HEAPHDR_HAS_TEMPROOT((duk_heaphdr *) h) ? 1 : 0),
38558 (long) (DUK_HEAPHDR_HAS_FINALIZABLE((duk_heaphdr *) h) ? 1 : 0),
38559 (long) (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) h) ? 1 : 0));
38560 }
38561#endif
38562}
38563
38564DUK_LOCAL void duk__print_hstring(duk__dprint_state *st, duk_hstring *h, duk_bool_t quotes) {
38565 duk_fixedbuffer *fb = st->fb;
38566 const duk_uint8_t *p;
38567 const duk_uint8_t *p_end;
38568
38569 /* terminal type: no depth check */
38570
38571 if (duk_fb_is_full(fb)) {
38572 return;
38573 }
38574
38575 duk__print_shared_heaphdr_string(st, &h->hdr);
38576
38577 if (!h) {
38578 duk_fb_put_cstring(fb, "NULL");
38579 return;
38580 }
38581
38582 p = DUK_HSTRING_GET_DATA(h);
38583 p_end = p + DUK_HSTRING_GET_BYTELEN(h);
38584
38585 if (p_end > p && p[0] == DUK_ASC_UNDERSCORE) {
38586 /* if property key begins with underscore, encode it with
38587 * forced quotes (e.g. "_Foo") to distinguish it from encoded
38588 * internal properties (e.g. \xffBar -> _Bar).
38589 */
38590 quotes = 1;
38591 }
38592
38593 if (quotes) {
38594 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_DOUBLEQUOTE);
38595 }
38596 while (p < p_end) {
38597 duk_uint8_t ch = *p++;
38598
38599 /* two special escapes: '\' and '"', other printables as is */
38600 if (ch == '\\') {
38601 duk_fb_sprintf(fb, "\\\\");
38602 } else if (ch == '"') {
38603 duk_fb_sprintf(fb, "\\\"");
38604 } else if (ch >= 0x20 && ch <= 0x7e) {
38605 duk_fb_put_byte(fb, ch);
38606 } else if (ch == 0xff && !quotes) {
38607 /* encode \xffBar as _Bar if no quotes are applied, this is for
38608 * readable internal keys.
38609 */
38610 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_UNDERSCORE);
38611 } else {
38612 duk_fb_sprintf(fb, "\\x%02lx", (unsigned long) ch);
38613 }
38614 }
38615 if (quotes) {
38616 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_DOUBLEQUOTE);
38617 }
38618#if defined(DUK_USE_REFERENCE_COUNTING)
38619 /* XXX: limit to quoted strings only, to save keys from being cluttered? */
38620 duk_fb_sprintf(fb, "/%lu", (unsigned long) DUK_HEAPHDR_GET_REFCOUNT(&h->hdr));
38621#endif
38622}
38623
38624#define DUK__COMMA() do { \
38625 if (first) { \
38626 first = 0; \
38627 } else { \
38628 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_COMMA); \
38629 } \
38630 } while (0)
38631
38632DUK_LOCAL void duk__print_hobject(duk__dprint_state *st, duk_hobject *h) {
38633 duk_fixedbuffer *fb = st->fb;
38634 duk_uint_fast32_t i;
38635 duk_tval *tv;
38637 duk_bool_t first = 1;
38638 const char *brace1 = "{";
38639 const char *brace2 = "}";
38640 duk_bool_t pushed_loopstack = 0;
38641
38642 if (duk_fb_is_full(fb)) {
38643 return;
38644 }
38645
38646 duk__print_shared_heaphdr(st, &h->hdr);
38647
38648 if (h && DUK_HOBJECT_HAS_ARRAY_PART(h)) {
38649 brace1 = "[";
38650 brace2 = "]";
38651 }
38652
38653 if (!h) {
38654 duk_fb_put_cstring(fb, "NULL");
38655 goto finished;
38656 }
38657
38658 if (st->depth >= st->depth_limit) {
38659 const char *subtype = "generic";
38660
38661 if (DUK_HOBJECT_IS_COMPFUNC(h)) {
38662 subtype = "compfunc";
38663 } else if (DUK_HOBJECT_IS_NATFUNC(h)) {
38664 subtype = "natfunc";
38665 } else if (DUK_HOBJECT_IS_THREAD(h)) {
38666 subtype = "thread";
38667 } else if (DUK_HOBJECT_IS_BUFOBJ(h)) {
38668 subtype = "bufobj";
38669 } else if (DUK_HOBJECT_IS_ARRAY(h)) {
38670 subtype = "array";
38671 }
38672 duk_fb_sprintf(fb, "%sobject/%s %p%s", (const char *) brace1, subtype, (void *) h, (const char *) brace2);
38673 return;
38674 }
38675
38676 for (i = 0; i < (duk_uint_fast32_t) st->loop_stack_index; i++) {
38677 if (st->loop_stack[i] == h) {
38678 duk_fb_sprintf(fb, "%sLOOP:%p%s", (const char *) brace1, (void *) h, (const char *) brace2);
38679 return;
38680 }
38681 }
38682
38683 /* after this, return paths should 'goto finished' for decrement */
38684 st->depth++;
38685
38686 if (st->loop_stack_index >= st->loop_stack_limit) {
38687 duk_fb_sprintf(fb, "%sOUT-OF-LOOP-STACK%s", (const char *) brace1, (const char *) brace2);
38688 goto finished;
38689 }
38690 st->loop_stack[st->loop_stack_index++] = h;
38691 pushed_loopstack = 1;
38692
38693 /*
38694 * Notation: double underscore used for internal properties which are not
38695 * stored in the property allocation (e.g. '__valstack').
38696 */
38697
38698 duk_fb_put_cstring(fb, brace1);
38699
38700 if (DUK_HOBJECT_GET_PROPS(NULL, h)) {
38701 duk_uint32_t a_limit;
38702
38703 a_limit = DUK_HOBJECT_GET_ASIZE(h);
38704 if (st->internal) {
38705 /* dump all allocated entries, unused entries print as 'unused',
38706 * note that these may extend beyond current 'length' and look
38707 * a bit funny.
38708 */
38709 } else {
38710 /* leave out trailing 'unused' elements */
38711 while (a_limit > 0) {
38712 tv = DUK_HOBJECT_A_GET_VALUE_PTR(NULL, h, a_limit - 1);
38713 if (!DUK_TVAL_IS_UNUSED(tv)) {
38714 break;
38715 }
38716 a_limit--;
38717 }
38718 }
38719
38720 for (i = 0; i < a_limit; i++) {
38721 tv = DUK_HOBJECT_A_GET_VALUE_PTR(NULL, h, i);
38722 DUK__COMMA();
38723 duk__print_tval(st, tv);
38724 }
38725 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(h); i++) {
38726 key = DUK_HOBJECT_E_GET_KEY(NULL, h, i);
38727 if (!key) {
38728 continue;
38729 }
38730 if (!st->internal && DUK_HSTRING_HAS_HIDDEN(key)) {
38731 continue;
38732 }
38733 DUK__COMMA();
38734 duk__print_hstring(st, key, 0);
38735 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_COLON);
38736 if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(NULL, h, i)) {
38737 duk_fb_sprintf(fb, "[get:%p,set:%p]",
38738 (void *) DUK_HOBJECT_E_GET_VALUE(NULL, h, i).a.get,
38739 (void *) DUK_HOBJECT_E_GET_VALUE(NULL, h, i).a.set);
38740 } else {
38741 tv = &DUK_HOBJECT_E_GET_VALUE(NULL, h, i).v;
38742 duk__print_tval(st, tv);
38743 }
38744 if (st->heavy) {
38745 duk_fb_sprintf(fb, "<%02lx>", (unsigned long) DUK_HOBJECT_E_GET_FLAGS(NULL, h, i));
38746 }
38747 }
38748 }
38749 if (st->internal) {
38750 if (DUK_HOBJECT_HAS_EXTENSIBLE(h)) {
38751 DUK__COMMA(); duk_fb_sprintf(fb, "__extensible:true");
38752 }
38753 if (DUK_HOBJECT_HAS_CONSTRUCTABLE(h)) {
38754 DUK__COMMA(); duk_fb_sprintf(fb, "__constructable:true");
38755 }
38756 if (DUK_HOBJECT_HAS_BOUNDFUNC(h)) {
38757 DUK__COMMA(); duk_fb_sprintf(fb, "__boundfunc:true");
38758 }
38759 if (DUK_HOBJECT_HAS_COMPFUNC(h)) {
38760 DUK__COMMA(); duk_fb_sprintf(fb, "__compfunc:true");
38761 }
38762 if (DUK_HOBJECT_HAS_NATFUNC(h)) {
38763 DUK__COMMA(); duk_fb_sprintf(fb, "__natfunc:true");
38764 }
38765 if (DUK_HOBJECT_HAS_BUFOBJ(h)) {
38766 DUK__COMMA(); duk_fb_sprintf(fb, "__bufobj:true");
38767 }
38768 if (DUK_HOBJECT_HAS_THREAD(h)) {
38769 DUK__COMMA(); duk_fb_sprintf(fb, "__thread:true");
38770 }
38771 if (DUK_HOBJECT_HAS_ARRAY_PART(h)) {
38772 DUK__COMMA(); duk_fb_sprintf(fb, "__array_part:true");
38773 }
38774 if (DUK_HOBJECT_HAS_STRICT(h)) {
38775 DUK__COMMA(); duk_fb_sprintf(fb, "__strict:true");
38776 }
38777 if (DUK_HOBJECT_HAS_NOTAIL(h)) {
38778 DUK__COMMA(); duk_fb_sprintf(fb, "__notail:true");
38779 }
38780 if (DUK_HOBJECT_HAS_NEWENV(h)) {
38781 DUK__COMMA(); duk_fb_sprintf(fb, "__newenv:true");
38782 }
38783 if (DUK_HOBJECT_HAS_NAMEBINDING(h)) {
38784 DUK__COMMA(); duk_fb_sprintf(fb, "__namebinding:true");
38785 }
38786 if (DUK_HOBJECT_HAS_CREATEARGS(h)) {
38787 DUK__COMMA(); duk_fb_sprintf(fb, "__createargs:true");
38788 }
38789 if (DUK_HOBJECT_HAS_ENVRECCLOSED(h)) {
38790 DUK__COMMA(); duk_fb_sprintf(fb, "__envrecclosed:true");
38791 }
38792 if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)) {
38793 DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_array:true");
38794 }
38795 if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(h)) {
38796 DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_stringobj:true");
38797 }
38798 if (DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h)) {
38799 DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_arguments:true");
38800 }
38801 if (DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(h)) {
38802 DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_dukfunc:true");
38803 }
38804 if (DUK_HOBJECT_IS_BUFOBJ(h)) {
38805 DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_bufobj:true");
38806 }
38807 if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(h)) {
38808 DUK__COMMA(); duk_fb_sprintf(fb, "__exotic_proxyobj:true");
38809 }
38810 }
38811
38812 if (st->internal && DUK_HOBJECT_IS_ARRAY(h)) {
38813 duk_harray *a = (duk_harray *) h;
38814 DUK__COMMA(); duk_fb_sprintf(fb, "__length:%ld", (long) a->length);
38815 DUK__COMMA(); duk_fb_sprintf(fb, "__length_nonwritable:%ld", (long) a->length_nonwritable);
38816 } else if (st->internal && DUK_HOBJECT_IS_COMPFUNC(h)) {
38817 duk_hcompfunc *f = (duk_hcompfunc *) h;
38818 DUK__COMMA(); duk_fb_put_cstring(fb, "__data:");
38819 duk__print_hbuffer(st, (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(NULL, f));
38820 DUK__COMMA(); duk_fb_put_cstring(fb, "__lexenv:"); duk__print_hobject(st, DUK_HCOMPFUNC_GET_LEXENV(NULL, f));
38821 DUK__COMMA(); duk_fb_put_cstring(fb, "__varenv:"); duk__print_hobject(st, DUK_HCOMPFUNC_GET_VARENV(NULL, f));
38822 DUK__COMMA(); duk_fb_sprintf(fb, "__nregs:%ld", (long) f->nregs);
38823 DUK__COMMA(); duk_fb_sprintf(fb, "__nargs:%ld", (long) f->nargs);
38824#if defined(DUK_USE_DEBUGGER_SUPPORT)
38825 DUK__COMMA(); duk_fb_sprintf(fb, "__start_line:%ld", (long) f->start_line);
38826 DUK__COMMA(); duk_fb_sprintf(fb, "__end_line:%ld", (long) f->end_line);
38827#endif
38828 DUK__COMMA(); duk_fb_put_cstring(fb, "__data:");
38829 duk__print_hbuffer(st, (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(NULL, f));
38830 } else if (st->internal && DUK_HOBJECT_IS_NATFUNC(h)) {
38831 duk_hnatfunc *f = (duk_hnatfunc *) h;
38832 DUK__COMMA(); duk_fb_sprintf(fb, "__func:");
38833 duk_fb_put_funcptr(fb, (duk_uint8_t *) &f->func, sizeof(f->func));
38834 DUK__COMMA(); duk_fb_sprintf(fb, "__nargs:%ld", (long) f->nargs);
38835 DUK__COMMA(); duk_fb_sprintf(fb, "__magic:%ld", (long) f->magic);
38836#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
38837 } else if (st->internal && DUK_HOBJECT_IS_BUFOBJ(h)) {
38838 duk_hbufobj *b = (duk_hbufobj *) h;
38839 DUK__COMMA(); duk_fb_sprintf(fb, "__buf:");
38840 duk__print_hbuffer(st, (duk_hbuffer *) b->buf);
38841 DUK__COMMA(); duk_fb_sprintf(fb, "__buf_prop:");
38842 duk__print_hobject(st, (duk_hobject *) b->buf_prop);
38843 DUK__COMMA(); duk_fb_sprintf(fb, "__offset:%ld", (long) b->offset);
38844 DUK__COMMA(); duk_fb_sprintf(fb, "__length:%ld", (long) b->length);
38845 DUK__COMMA(); duk_fb_sprintf(fb, "__shift:%ld", (long) b->shift);
38846 DUK__COMMA(); duk_fb_sprintf(fb, "__elemtype:%ld", (long) b->elem_type);
38847#endif
38848 } else if (st->internal && DUK_HOBJECT_IS_THREAD(h)) {
38849 duk_hthread *t = (duk_hthread *) h;
38850 DUK__COMMA(); duk_fb_sprintf(fb, "__strict:%ld", (long) t->strict);
38851 DUK__COMMA(); duk_fb_sprintf(fb, "__state:%ld", (long) t->state);
38852 DUK__COMMA(); duk_fb_sprintf(fb, "__unused1:%ld", (long) t->unused1);
38853 DUK__COMMA(); duk_fb_sprintf(fb, "__unused2:%ld", (long) t->unused2);
38854 DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_max:%ld", (long) t->valstack_max);
38855 DUK__COMMA(); duk_fb_sprintf(fb, "__callstack_max:%ld", (long) t->callstack_max);
38856 DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack_max:%ld", (long) t->catchstack_max);
38857 DUK__COMMA(); duk_fb_sprintf(fb, "__valstack:%p", (void *) t->valstack);
38858 DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_end:%p/%ld", (void *) t->valstack_end, (long) (t->valstack_end - t->valstack));
38859 DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_bottom:%p/%ld", (void *) t->valstack_bottom, (long) (t->valstack_bottom - t->valstack));
38860 DUK__COMMA(); duk_fb_sprintf(fb, "__valstack_top:%p/%ld", (void *) t->valstack_top, (long) (t->valstack_top - t->valstack));
38861 DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack:%p", (void *) t->catchstack);
38862 DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack_size:%ld", (long) t->catchstack_size);
38863 DUK__COMMA(); duk_fb_sprintf(fb, "__catchstack_top:%ld", (long) t->catchstack_top);
38864 DUK__COMMA(); duk_fb_sprintf(fb, "__resumer:"); duk__print_hobject(st, (duk_hobject *) t->resumer);
38865 /* XXX: print built-ins array? */
38866
38867 }
38868#if defined(DUK_USE_REFERENCE_COUNTING)
38869 if (st->internal) {
38870 DUK__COMMA(); duk_fb_sprintf(fb, "__refcount:%lu", (unsigned long) DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h));
38871 }
38872#endif
38873 if (st->internal) {
38874 DUK__COMMA(); duk_fb_sprintf(fb, "__class:%ld", (long) DUK_HOBJECT_GET_CLASS_NUMBER(h));
38875 }
38876
38877 DUK__COMMA(); duk_fb_sprintf(fb, "__heapptr:%p", (void *) h); /* own pointer */
38878
38879 /* prototype should be last, for readability */
38880 if (DUK_HOBJECT_GET_PROTOTYPE(NULL, h)) {
38881 if (st->follow_proto) {
38882 DUK__COMMA(); duk_fb_put_cstring(fb, "__prototype:"); duk__print_hobject(st, DUK_HOBJECT_GET_PROTOTYPE(NULL, h));
38883 } else {
38884 DUK__COMMA(); duk_fb_sprintf(fb, "__prototype:%p", (void *) DUK_HOBJECT_GET_PROTOTYPE(NULL, h));
38885 }
38886 }
38887
38888 duk_fb_put_cstring(fb, brace2);
38889
38890#if defined(DUK_USE_HOBJECT_HASH_PART)
38891 if (st->heavy && DUK_HOBJECT_GET_HSIZE(h) > 0) {
38892 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LANGLE);
38893 for (i = 0; i < DUK_HOBJECT_GET_HSIZE(h); i++) {
38894 duk_uint_t h_idx = DUK_HOBJECT_H_GET_INDEX(NULL, h, i);
38895 if (i > 0) {
38896 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_COMMA);
38897 }
38898 if (h_idx == DUK_HOBJECT_HASHIDX_UNUSED) {
38899 duk_fb_sprintf(fb, "u");
38900 } else if (h_idx == DUK_HOBJECT_HASHIDX_DELETED) {
38901 duk_fb_sprintf(fb, "d");
38902 } else {
38903 duk_fb_sprintf(fb, "%ld", (long) h_idx);
38904 }
38905 }
38906 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RANGLE);
38907 }
38908#endif
38909
38910 finished:
38911 st->depth--;
38912 if (pushed_loopstack) {
38913 st->loop_stack_index--;
38914 st->loop_stack[st->loop_stack_index] = NULL;
38915 }
38916}
38917
38918DUK_LOCAL void duk__print_hbuffer(duk__dprint_state *st, duk_hbuffer *h) {
38919 duk_fixedbuffer *fb = st->fb;
38920 duk_size_t i, n;
38921 duk_uint8_t *p;
38922
38923 if (duk_fb_is_full(fb)) {
38924 return;
38925 }
38926
38927 /* terminal type: no depth check */
38928
38929 if (!h) {
38930 duk_fb_put_cstring(fb, "NULL");
38931 return;
38932 }
38933
38934 if (DUK_HBUFFER_HAS_DYNAMIC(h)) {
38935 if (DUK_HBUFFER_HAS_EXTERNAL(h)) {
38937 duk_fb_sprintf(fb, "buffer:external:%p:%ld",
38938 (void *) DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(NULL, g),
38939 (long) DUK_HBUFFER_EXTERNAL_GET_SIZE(g));
38940 } else {
38942 duk_fb_sprintf(fb, "buffer:dynamic:%p:%ld",
38943 (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(NULL, g),
38944 (long) DUK_HBUFFER_DYNAMIC_GET_SIZE(g));
38945 }
38946 } else {
38947 duk_fb_sprintf(fb, "buffer:fixed:%ld", (long) DUK_HBUFFER_GET_SIZE(h));
38948 }
38949
38950#if defined(DUK_USE_REFERENCE_COUNTING)
38951 duk_fb_sprintf(fb, "/%lu", (unsigned long) DUK_HEAPHDR_GET_REFCOUNT(&h->hdr));
38952#endif
38953
38954 if (st->hexdump) {
38955 duk_fb_sprintf(fb, "=[");
38956 n = DUK_HBUFFER_GET_SIZE(h);
38957 p = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(NULL, h);
38958 for (i = 0; i < n; i++) {
38959 duk_fb_sprintf(fb, "%02lx", (unsigned long) p[i]);
38960 }
38961 duk_fb_sprintf(fb, "]");
38962 }
38963}
38964
38965DUK_LOCAL void duk__print_heaphdr(duk__dprint_state *st, duk_heaphdr *h) {
38966 duk_fixedbuffer *fb = st->fb;
38967
38968 if (duk_fb_is_full(fb)) {
38969 return;
38970 }
38971
38972 if (!h) {
38973 duk_fb_put_cstring(fb, "NULL");
38974 return;
38975 }
38976
38977 switch (DUK_HEAPHDR_GET_TYPE(h)) {
38978 case DUK_HTYPE_STRING:
38979 duk__print_hstring(st, (duk_hstring *) h, 1);
38980 break;
38981 case DUK_HTYPE_OBJECT:
38982 duk__print_hobject(st, (duk_hobject *) h);
38983 break;
38984 case DUK_HTYPE_BUFFER:
38985 duk__print_hbuffer(st, (duk_hbuffer *) h);
38986 break;
38987 default:
38988 duk_fb_sprintf(fb, "[unknown htype %ld]", (long) DUK_HEAPHDR_GET_TYPE(h));
38989 break;
38990 }
38991}
38992
38993DUK_LOCAL void duk__print_tval(duk__dprint_state *st, duk_tval *tv) {
38994 duk_fixedbuffer *fb = st->fb;
38995
38996 if (duk_fb_is_full(fb)) {
38997 return;
38998 }
38999
39000 /* depth check is done when printing an actual type */
39001
39002 if (st->heavy) {
39003 duk_fb_sprintf(fb, "(%p)", (void *) tv);
39004 }
39005
39006 if (!tv) {
39007 duk_fb_put_cstring(fb, "NULL");
39008 return;
39009 }
39010
39011 if (st->binary) {
39012 duk_size_t i;
39013 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LBRACKET);
39014 for (i = 0; i < (duk_size_t) sizeof(*tv); i++) {
39015 duk_fb_sprintf(fb, "%02lx", (unsigned long) ((duk_uint8_t *)tv)[i]);
39016 }
39017 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RBRACKET);
39018 }
39019
39020 if (st->heavy) {
39021 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_LANGLE);
39022 }
39023 switch (DUK_TVAL_GET_TAG(tv)) {
39024 case DUK_TAG_UNDEFINED: {
39025 duk_fb_put_cstring(fb, "undefined");
39026 break;
39027 }
39028 case DUK_TAG_UNUSED: {
39029 duk_fb_put_cstring(fb, "unused");
39030 break;
39031 }
39032 case DUK_TAG_NULL: {
39033 duk_fb_put_cstring(fb, "null");
39034 break;
39035 }
39036 case DUK_TAG_BOOLEAN: {
39037 duk_fb_put_cstring(fb, DUK_TVAL_GET_BOOLEAN(tv) ? "true" : "false");
39038 break;
39039 }
39040 case DUK_TAG_STRING: {
39041 /* Note: string is a terminal heap object, so no depth check here */
39042 duk__print_hstring(st, DUK_TVAL_GET_STRING(tv), 1);
39043 break;
39044 }
39045 case DUK_TAG_OBJECT: {
39046 duk__print_hobject(st, DUK_TVAL_GET_OBJECT(tv));
39047 break;
39048 }
39049 case DUK_TAG_BUFFER: {
39050 duk__print_hbuffer(st, DUK_TVAL_GET_BUFFER(tv));
39051 break;
39052 }
39053 case DUK_TAG_POINTER: {
39054 duk_fb_sprintf(fb, "pointer:%p", (void *) DUK_TVAL_GET_POINTER(tv));
39055 break;
39056 }
39057 case DUK_TAG_LIGHTFUNC: {
39058 duk_c_function func;
39059 duk_small_uint_t lf_flags;
39060
39061 DUK_TVAL_GET_LIGHTFUNC(tv, func, lf_flags);
39062 duk_fb_sprintf(fb, "lightfunc:");
39063 duk_fb_put_funcptr(fb, (duk_uint8_t *) &func, sizeof(func));
39064 duk_fb_sprintf(fb, ":%04lx", (long) lf_flags);
39065 break;
39066 }
39067#if defined(DUK_USE_FASTINT)
39068 case DUK_TAG_FASTINT:
39069#endif
39070 default: {
39071 /* IEEE double is approximately 16 decimal digits; print a couple extra */
39072 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
39073 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
39074 duk_fb_sprintf(fb, "%.18g", (double) DUK_TVAL_GET_NUMBER(tv));
39075 break;
39076 }
39077 }
39078 if (st->heavy) {
39079 duk_fb_put_byte(fb, (duk_uint8_t) DUK_ASC_RANGLE);
39080 }
39081}
39082
39083DUK_LOCAL void duk__print_instr(duk__dprint_state *st, duk_instr_t ins) {
39084 duk_fixedbuffer *fb = st->fb;
39085 duk_small_int_t op;
39086 const char *op_name;
39087
39088 op = (duk_small_int_t) DUK_DEC_OP(ins);
39089 op_name = duk__bc_optab[op];
39090
39091 /* XXX: option to fix opcode length so it lines up nicely */
39092
39093 if (op == DUK_OP_JUMP) {
39094 duk_int_t diff1 = DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS; /* from next pc */
39095 duk_int_t diff2 = diff1 + 1; /* from curr pc */
39096
39097 duk_fb_sprintf(fb, "%s %ld (to pc%c%ld)",
39098 (const char *) op_name, (long) diff1,
39099 (int) (diff2 >= 0 ? '+' : '-'), /* char format: use int */
39100 (long) (diff2 >= 0 ? diff2 : -diff2));
39101 } else {
39102 duk_fb_sprintf(fb, "%s %ld, %ld, %ld",
39103 (const char *) op_name, (long) DUK_DEC_A(ins),
39104 (long) DUK_DEC_B(ins), (long) DUK_DEC_C(ins));
39105 }
39106}
39107
39108DUK_LOCAL void duk__print_opcode(duk__dprint_state *st, duk_small_int_t opcode) {
39109 duk_fixedbuffer *fb = st->fb;
39110
39111 if (opcode < DUK_BC_OP_MIN || opcode > DUK_BC_OP_MAX) {
39112 duk_fb_sprintf(fb, "?(%ld)", (long) opcode);
39113 } else {
39114 duk_fb_sprintf(fb, "%s", (const char *) duk__bc_optab[opcode]);
39115 }
39116}
39117
39118DUK_INTERNAL duk_int_t duk_debug_vsnprintf(char *str, duk_size_t size, const char *format, va_list ap) {
39119 duk_fixedbuffer fb;
39120 const char *p = format;
39121 const char *p_end = p + DUK_STRLEN(format);
39122 duk_int_t retval;
39123
39124 DUK_MEMZERO(&fb, sizeof(fb));
39125 fb.buffer = (duk_uint8_t *) str;
39126 fb.length = size;
39127 fb.offset = 0;
39128 fb.truncated = 0;
39129
39130 while (p < p_end) {
39131 char ch = *p++;
39132 const char *p_begfmt = NULL;
39133 duk_bool_t got_exclamation = 0;
39134 duk_bool_t got_long = 0; /* %lf, %ld etc */
39135 duk__dprint_state st;
39136
39137 if (ch != DUK_ASC_PERCENT) {
39138 duk_fb_put_byte(&fb, (duk_uint8_t) ch);
39139 continue;
39140 }
39141
39142 /*
39143 * Format tag parsing. Since we don't understand all the
39144 * possible format tags allowed, we just scan for a terminating
39145 * specifier and keep track of relevant modifiers that we do
39146 * understand. See man 3 printf.
39147 */
39148
39149 DUK_MEMZERO(&st, sizeof(st));
39150 st.fb = &fb;
39151 st.depth = 0;
39152 st.depth_limit = 1;
39153 st.loop_stack_index = 0;
39154 st.loop_stack_limit = DUK__LOOP_STACK_DEPTH;
39155
39156 p_begfmt = p - 1;
39157 while (p < p_end) {
39158 ch = *p++;
39159
39160 if (ch == DUK_ASC_STAR) {
39161 /* unsupported: would consume multiple args */
39162 goto error;
39163 } else if (ch == DUK_ASC_PERCENT) {
39164 duk_fb_put_byte(&fb, (duk_uint8_t) DUK_ASC_PERCENT);
39165 break;
39166 } else if (ch == DUK_ASC_EXCLAMATION) {
39167 got_exclamation = 1;
39168 } else if (!got_exclamation && ch == DUK_ASC_LC_L) {
39169 got_long = 1;
39170 } else if (got_exclamation && ch == DUK_ASC_LC_D) {
39171 st.depth_limit = DUK__DEEP_DEPTH_LIMIT;
39172 } else if (got_exclamation && ch == DUK_ASC_LC_P) {
39173 st.follow_proto = 1;
39174 } else if (got_exclamation && ch == DUK_ASC_LC_I) {
39175 st.internal = 1;
39176 } else if (got_exclamation && ch == DUK_ASC_LC_X) {
39177 st.hexdump = 1;
39178 } else if (got_exclamation && ch == DUK_ASC_LC_H) {
39179 st.heavy = 1;
39180 } else if (got_exclamation && ch == DUK_ASC_ATSIGN) {
39181 st.pointer = 1;
39182 } else if (got_exclamation && ch == DUK_ASC_HASH) {
39183 st.binary = 1;
39184 } else if (got_exclamation && ch == DUK_ASC_UC_T) {
39185 duk_tval *t = va_arg(ap, duk_tval *);
39186 if (st.pointer && !st.heavy) {
39187 duk_fb_sprintf(&fb, "(%p)", (void *) t);
39188 }
39189 duk__print_tval(&st, t);
39190 break;
39191 } else if (got_exclamation && ch == DUK_ASC_UC_O) {
39192 duk_heaphdr *t = va_arg(ap, duk_heaphdr *);
39193 if (st.pointer && !st.heavy) {
39194 duk_fb_sprintf(&fb, "(%p)", (void *) t);
39195 }
39196 duk__print_heaphdr(&st, t);
39197 break;
39198 } else if (got_exclamation && ch == DUK_ASC_UC_I) {
39199 duk_instr_t t = va_arg(ap, duk_instr_t);
39200 duk__print_instr(&st, t);
39201 break;
39202 } else if (got_exclamation && ch == DUK_ASC_UC_C) {
39203 long t = va_arg(ap, long);
39204 duk__print_opcode(&st, (duk_small_int_t) t);
39205 break;
39206 } else if (!got_exclamation && strchr(DUK__ALLOWED_STANDARD_SPECIFIERS, (int) ch)) {
39207 char fmtbuf[DUK__MAX_FORMAT_TAG_LENGTH];
39208 duk_size_t fmtlen;
39209
39210 DUK_ASSERT(p >= p_begfmt);
39211 fmtlen = (duk_size_t) (p - p_begfmt);
39212 if (fmtlen >= sizeof(fmtbuf)) {
39213 /* format is too large, abort */
39214 goto error;
39215 }
39216 DUK_MEMZERO(fmtbuf, sizeof(fmtbuf));
39217 DUK_MEMCPY(fmtbuf, p_begfmt, fmtlen);
39218
39219 /* assume exactly 1 arg, which is why '*' is forbidden; arg size still
39220 * depends on type though.
39221 */
39222
39223 if (ch == DUK_ASC_LC_F || ch == DUK_ASC_LC_G || ch == DUK_ASC_LC_E) {
39224 /* %f and %lf both consume a 'long' */
39225 double arg = va_arg(ap, double);
39226 duk_fb_sprintf(&fb, fmtbuf, arg);
39227 } else if (ch == DUK_ASC_LC_D && got_long) {
39228 /* %ld */
39229 long arg = va_arg(ap, long);
39230 duk_fb_sprintf(&fb, fmtbuf, arg);
39231 } else if (ch == DUK_ASC_LC_D) {
39232 /* %d; only 16 bits are guaranteed */
39233 int arg = va_arg(ap, int);
39234 duk_fb_sprintf(&fb, fmtbuf, arg);
39235 } else if (ch == DUK_ASC_LC_U && got_long) {
39236 /* %lu */
39237 unsigned long arg = va_arg(ap, unsigned long);
39238 duk_fb_sprintf(&fb, fmtbuf, arg);
39239 } else if (ch == DUK_ASC_LC_U) {
39240 /* %u; only 16 bits are guaranteed */
39241 unsigned int arg = va_arg(ap, unsigned int);
39242 duk_fb_sprintf(&fb, fmtbuf, arg);
39243 } else if (ch == DUK_ASC_LC_X && got_long) {
39244 /* %lx */
39245 unsigned long arg = va_arg(ap, unsigned long);
39246 duk_fb_sprintf(&fb, fmtbuf, arg);
39247 } else if (ch == DUK_ASC_LC_X) {
39248 /* %x; only 16 bits are guaranteed */
39249 unsigned int arg = va_arg(ap, unsigned int);
39250 duk_fb_sprintf(&fb, fmtbuf, arg);
39251 } else if (ch == DUK_ASC_LC_S) {
39252 /* %s */
39253 const char *arg = va_arg(ap, const char *);
39254 if (arg == NULL) {
39255 /* '%s' and NULL is not portable, so special case
39256 * it for debug printing.
39257 */
39258 duk_fb_sprintf(&fb, "NULL");
39259 } else {
39260 duk_fb_sprintf(&fb, fmtbuf, arg);
39261 }
39262 } else if (ch == DUK_ASC_LC_P) {
39263 /* %p */
39264 void *arg = va_arg(ap, void *);
39265 if (arg == NULL) {
39266 /* '%p' and NULL is portable, but special case it
39267 * anyway to get a standard NULL marker in logs.
39268 */
39269 duk_fb_sprintf(&fb, "NULL");
39270 } else {
39271 duk_fb_sprintf(&fb, fmtbuf, arg);
39272 }
39273 } else if (ch == DUK_ASC_LC_C) {
39274 /* '%c', passed concretely as int */
39275 int arg = va_arg(ap, int);
39276 duk_fb_sprintf(&fb, fmtbuf, arg);
39277 } else {
39278 /* Should not happen. */
39279 duk_fb_sprintf(&fb, "INVALID-FORMAT(%s)", (const char *) fmtbuf);
39280 }
39281 break;
39282 } else {
39283 /* ignore */
39284 }
39285 }
39286 }
39287 goto done;
39288
39289 error:
39290 duk_fb_put_cstring(&fb, "FMTERR");
39291 /* fall through */
39292
39293 done:
39294 retval = (duk_int_t) fb.offset;
39295 duk_fb_put_byte(&fb, (duk_uint8_t) 0);
39296
39297 /* return total chars written excluding terminator */
39298 return retval;
39299}
39300
39301#if 0 /*unused*/
39302DUK_INTERNAL duk_int_t duk_debug_snprintf(char *str, duk_size_t size, const char *format, ...) {
39303 duk_int_t retval;
39304 va_list ap;
39305 va_start(ap, format);
39306 retval = duk_debug_vsnprintf(str, size, format, ap);
39307 va_end(ap);
39308 return retval;
39309}
39310#endif
39311
39312/* Formatting function pointers is tricky: there is no standard pointer for
39313 * function pointers and the size of a function pointer may depend on the
39314 * specific pointer type. This helper formats a function pointer based on
39315 * its memory layout to get something useful on most platforms.
39316 */
39317DUK_INTERNAL void duk_debug_format_funcptr(char *buf, duk_size_t buf_size, duk_uint8_t *fptr, duk_size_t fptr_size) {
39318 duk_size_t i;
39319 duk_uint8_t *p = (duk_uint8_t *) buf;
39320 duk_uint8_t *p_end = (duk_uint8_t *) (buf + buf_size - 1);
39321
39322 DUK_MEMZERO(buf, buf_size);
39323
39324 for (i = 0; i < fptr_size; i++) {
39325 duk_int_t left = (duk_int_t) (p_end - p);
39326 duk_uint8_t ch;
39327 if (left <= 0) {
39328 break;
39329 }
39330
39331 /* Quite approximate but should be useful for little and big endian. */
39332#if defined(DUK_USE_INTEGER_BE)
39333 ch = fptr[i];
39334#else
39335 ch = fptr[fptr_size - 1 - i];
39336#endif
39337 p += DUK_SNPRINTF((char *) p, left, "%02lx", (unsigned long) ch);
39338 }
39339}
39340
39341#endif /* DUK_USE_DEBUG */
39342
39343/* automatic undefs */
39344#undef DUK__ALLOWED_STANDARD_SPECIFIERS
39345#undef DUK__COMMA
39346#undef DUK__DEEP_DEPTH_LIMIT
39347#undef DUK__LOOP_STACK_DEPTH
39348#undef DUK__MAX_FORMAT_TAG_LENGTH
39349/*
39350 * Duktape debugger
39351 */
39352
39353/* #include duk_internal.h -> already included */
39354
39355#if defined(DUK_USE_DEBUGGER_SUPPORT)
39356
39357/*
39358 * Helper structs
39359 */
39360
39361typedef union {
39362 void *p;
39363 duk_uint_t b[1];
39364 /* Use b[] to access the size of the union, which is strictly not
39365 * correct. Can't use fixed size unless there's feature detection
39366 * for pointer byte size.
39367 */
39368} duk__ptr_union;
39369
39370/*
39371 * Detach handling
39372 */
39373
39374#define DUK__SET_CONN_BROKEN(thr,reason) do { \
39375 /* For now shared handler is fine. */ \
39376 duk__debug_do_detach1((thr)->heap, (reason)); \
39377 } while (0)
39378
39379DUK_LOCAL void duk__debug_do_detach1(duk_heap *heap, duk_int_t reason) {
39380 /* Can be called multiple times with no harm. Mark the transport
39381 * bad (dbg_read_cb == NULL) and clear state except for the detached
39382 * callback and the udata field. The detached callback is delayed
39383 * to the message loop so that it can be called between messages;
39384 * this avoids corner cases related to immediate debugger reattach
39385 * inside the detached callback.
39386 */
39387
39388 if (heap->dbg_detaching) {
39389 DUK_D(DUK_DPRINT("debugger already detaching, ignore detach1"));
39390 return;
39391 }
39392
39393 DUK_D(DUK_DPRINT("debugger transport detaching, marking transport broken"));
39394
39395 heap->dbg_detaching = 1; /* prevent multiple in-progress detaches */
39396
39397 if (heap->dbg_write_cb != NULL) {
39398 duk_hthread *thr;
39399
39400 thr = heap->heap_thread;
39401 DUK_ASSERT(thr != NULL);
39402
39403 duk_debug_write_notify(thr, DUK_DBG_CMD_DETACHING);
39404 duk_debug_write_int(thr, reason);
39405 duk_debug_write_eom(thr);
39406 }
39407
39408 heap->dbg_read_cb = NULL;
39409 heap->dbg_write_cb = NULL;
39410 heap->dbg_peek_cb = NULL;
39411 heap->dbg_read_flush_cb = NULL;
39412 heap->dbg_write_flush_cb = NULL;
39413 heap->dbg_request_cb = NULL;
39414 /* heap->dbg_detached_cb: keep */
39415 /* heap->dbg_udata: keep */
39416 /* heap->dbg_processing: keep on purpose to avoid debugger re-entry in detaching state */
39417 DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap);
39418 heap->dbg_state_dirty = 0;
39419 heap->dbg_force_restart = 0;
39420 heap->dbg_step_type = 0;
39421 heap->dbg_step_thread = NULL;
39422 heap->dbg_step_csindex = 0;
39423 heap->dbg_step_startline = 0;
39424 heap->dbg_have_next_byte = 0;
39425
39426 /* Ensure there are no stale active breakpoint pointers.
39427 * Breakpoint list is currently kept - we could empty it
39428 * here but we'd need to handle refcounts correctly, and
39429 * we'd need a 'thr' reference for that.
39430 *
39431 * XXX: clear breakpoint on either attach or detach?
39432 */
39433 heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL;
39434}
39435
39436DUK_LOCAL void duk__debug_do_detach2(duk_heap *heap) {
39437 duk_debug_detached_function detached_cb;
39438 void *detached_udata;
39439 duk_hthread *thr;
39440 duk_context *ctx;
39441
39442 thr = heap->heap_thread;
39443 DUK_ASSERT(thr != NULL);
39444 ctx = (duk_context *) thr;
39445
39446 /* Safe to call multiple times. */
39447
39448 detached_cb = heap->dbg_detached_cb;
39449 detached_udata = heap->dbg_udata;
39450 heap->dbg_detached_cb = NULL;
39451 heap->dbg_udata = NULL;
39452
39453 if (detached_cb) {
39454 /* Careful here: state must be wiped before the call
39455 * so that we can cleanly handle a re-attach from
39456 * inside the callback.
39457 */
39458 DUK_D(DUK_DPRINT("detached during message loop, delayed call to detached_cb"));
39459 detached_cb(ctx, detached_udata);
39460 }
39461
39462 heap->dbg_detaching = 0;
39463}
39464
39465DUK_INTERNAL void duk_debug_do_detach(duk_heap *heap) {
39466 duk__debug_do_detach1(heap, 0);
39467 duk__debug_do_detach2(heap);
39468}
39469
39470/* Called on a read/write error: NULL all callbacks except the detached
39471 * callback so that we never accidentally call them after a read/write
39472 * error has been indicated. This is especially important for the transport
39473 * I/O callbacks to fulfill guaranteed callback semantics.
39474 */
39475DUK_LOCAL void duk__debug_null_most_callbacks(duk_hthread *thr) {
39476 duk_heap *heap;
39477 heap = thr->heap;
39478 DUK_D(DUK_DPRINT("transport read/write error, NULL all callbacks expected detached"));
39479 heap->dbg_read_cb = NULL;
39480 heap->dbg_write_cb = NULL; /* this is especially critical to avoid another write call in detach1() */
39481 heap->dbg_peek_cb = NULL;
39482 heap->dbg_read_flush_cb = NULL;
39483 heap->dbg_write_flush_cb = NULL;
39484 heap->dbg_request_cb = NULL;
39485 /* keep heap->dbg_detached_cb */
39486}
39487
39488/*
39489 * Debug connection peek and flush primitives
39490 */
39491
39492DUK_INTERNAL duk_bool_t duk_debug_read_peek(duk_hthread *thr) {
39493 duk_heap *heap;
39494
39495 DUK_ASSERT(thr != NULL);
39496 heap = thr->heap;
39497 DUK_ASSERT(heap != NULL);
39498
39499 if (heap->dbg_read_cb == NULL) {
39500 DUK_D(DUK_DPRINT("attempt to peek in detached state, return zero (= no data)"));
39501 return 0;
39502 }
39503 if (heap->dbg_peek_cb == NULL) {
39504 DUK_DD(DUK_DDPRINT("no peek callback, return zero (= no data)"));
39505 return 0;
39506 }
39507
39508 return (duk_bool_t) (heap->dbg_peek_cb(heap->dbg_udata) > 0);
39509}
39510
39511DUK_INTERNAL void duk_debug_read_flush(duk_hthread *thr) {
39512 duk_heap *heap;
39513
39514 DUK_ASSERT(thr != NULL);
39515 heap = thr->heap;
39516 DUK_ASSERT(heap != NULL);
39517
39518 if (heap->dbg_read_cb == NULL) {
39519 DUK_D(DUK_DPRINT("attempt to read flush in detached state, ignore"));
39520 return;
39521 }
39522 if (heap->dbg_read_flush_cb == NULL) {
39523 DUK_DD(DUK_DDPRINT("no read flush callback, ignore"));
39524 return;
39525 }
39526
39527 heap->dbg_read_flush_cb(heap->dbg_udata);
39528}
39529
39530DUK_INTERNAL void duk_debug_write_flush(duk_hthread *thr) {
39531 duk_heap *heap;
39532
39533 DUK_ASSERT(thr != NULL);
39534 heap = thr->heap;
39535 DUK_ASSERT(heap != NULL);
39536
39537 if (heap->dbg_read_cb == NULL) {
39538 DUK_D(DUK_DPRINT("attempt to write flush in detached state, ignore"));
39539 return;
39540 }
39541 if (heap->dbg_write_flush_cb == NULL) {
39542 DUK_DD(DUK_DDPRINT("no write flush callback, ignore"));
39543 return;
39544 }
39545
39546 heap->dbg_write_flush_cb(heap->dbg_udata);
39547}
39548
39549/*
39550 * Debug connection skip primitives
39551 */
39552
39553/* Skip fully. */
39554DUK_INTERNAL void duk_debug_skip_bytes(duk_hthread *thr, duk_size_t length) {
39555 duk_uint8_t dummy[64];
39556 duk_size_t now;
39557
39558 DUK_ASSERT(thr != NULL);
39559
39560 while (length > 0) {
39561 now = (length > sizeof(dummy) ? sizeof(dummy) : length);
39562 duk_debug_read_bytes(thr, dummy, now);
39563 length -= now;
39564 }
39565}
39566
39567DUK_INTERNAL void duk_debug_skip_byte(duk_hthread *thr) {
39568 DUK_ASSERT(thr != NULL);
39569
39570 (void) duk_debug_read_byte(thr);
39571}
39572
39573/*
39574 * Debug connection read primitives
39575 */
39576
39577/* Peek ahead in the stream one byte. */
39578DUK_INTERNAL uint8_t duk_debug_peek_byte(duk_hthread *thr) {
39579 /* It is important not to call this if the last byte read was an EOM.
39580 * Reading ahead in this scenario would cause unnecessary blocking if
39581 * another message is not available.
39582 */
39583
39584 duk_uint8_t x;
39585
39586 x = duk_debug_read_byte(thr);
39587 thr->heap->dbg_have_next_byte = 1;
39588 thr->heap->dbg_next_byte = x;
39589 return x;
39590}
39591
39592/* Read fully. */
39593DUK_INTERNAL void duk_debug_read_bytes(duk_hthread *thr, duk_uint8_t *data, duk_size_t length) {
39594 duk_heap *heap;
39595 duk_uint8_t *p;
39596 duk_size_t left;
39597 duk_size_t got;
39598
39599 DUK_ASSERT(thr != NULL);
39600 heap = thr->heap;
39601 DUK_ASSERT(heap != NULL);
39602
39603 if (heap->dbg_read_cb == NULL) {
39604 DUK_D(DUK_DPRINT("attempt to read %ld bytes in detached state, return zero data", (long) length));
39605 goto fail;
39606 }
39607
39608 /* NOTE: length may be zero */
39609 p = data;
39610 if (length >= 1 && heap->dbg_have_next_byte) {
39611 heap->dbg_have_next_byte = 0;
39612 *p++ = heap->dbg_next_byte;
39613 }
39614 for (;;) {
39615 left = (duk_size_t) ((data + length) - p);
39616 if (left == 0) {
39617 break;
39618 }
39619 DUK_ASSERT(heap->dbg_read_cb != NULL);
39620 DUK_ASSERT(left >= 1);
39621#if defined(DUK_USE_DEBUGGER_TRANSPORT_TORTURE)
39622 left = 1;
39623#endif
39624 got = heap->dbg_read_cb(heap->dbg_udata, (char *) p, left);
39625 if (got == 0 || got > left) {
39626 DUK_D(DUK_DPRINT("connection error during read, return zero data"));
39627 duk__debug_null_most_callbacks(thr); /* avoid calling write callback in detach1() */
39628 DUK__SET_CONN_BROKEN(thr, 1);
39629 goto fail;
39630 }
39631 p += got;
39632 }
39633 return;
39634
39635 fail:
39636 DUK_MEMZERO((void *) data, (size_t) length);
39637}
39638
39639DUK_INTERNAL duk_uint8_t duk_debug_read_byte(duk_hthread *thr) {
39640 duk_uint8_t x;
39641
39642 x = 0; /* just in case callback is broken and won't write 'x' */
39643 duk_debug_read_bytes(thr, &x, 1);
39644 return x;
39645}
39646
39647DUK_LOCAL duk_uint32_t duk__debug_read_uint32_raw(duk_hthread *thr) {
39648 duk_uint8_t buf[4];
39649
39650 DUK_ASSERT(thr != NULL);
39651
39652 duk_debug_read_bytes(thr, buf, 4);
39653 return ((duk_uint32_t) buf[0] << 24) |
39654 ((duk_uint32_t) buf[1] << 16) |
39655 ((duk_uint32_t) buf[2] << 8) |
39656 (duk_uint32_t) buf[3];
39657}
39658
39659DUK_LOCAL duk_uint32_t duk__debug_read_int32_raw(duk_hthread *thr) {
39660 return (duk_int32_t) duk__debug_read_uint32_raw(thr);
39661}
39662
39663DUK_LOCAL duk_uint16_t duk__debug_read_uint16_raw(duk_hthread *thr) {
39664 duk_uint8_t buf[2];
39665
39666 DUK_ASSERT(thr != NULL);
39667
39668 duk_debug_read_bytes(thr, buf, 2);
39669 return ((duk_uint16_t) buf[0] << 8) |
39670 (duk_uint16_t) buf[1];
39671}
39672
39673DUK_INTERNAL duk_int32_t duk_debug_read_int(duk_hthread *thr) {
39674 duk_small_uint_t x;
39675 duk_small_uint_t t;
39676
39677 DUK_ASSERT(thr != NULL);
39678
39679 x = duk_debug_read_byte(thr);
39680 if (x >= 0xc0) {
39681 t = duk_debug_read_byte(thr);
39682 return (duk_int32_t) (((x - 0xc0) << 8) + t);
39683 } else if (x >= 0x80) {
39684 return (duk_int32_t) (x - 0x80);
39685 } else if (x == DUK_DBG_IB_INT4) {
39686 return (duk_int32_t) duk__debug_read_uint32_raw(thr);
39687 }
39688
39689 DUK_D(DUK_DPRINT("debug connection error: failed to decode int"));
39690 DUK__SET_CONN_BROKEN(thr, 1);
39691 return 0;
39692}
39693
39694DUK_LOCAL duk_hstring *duk__debug_read_hstring_raw(duk_hthread *thr, duk_uint32_t len) {
39695 duk_context *ctx = (duk_context *) thr;
39696 duk_uint8_t buf[31];
39697 duk_uint8_t *p;
39698
39699 if (len <= sizeof(buf)) {
39700 duk_debug_read_bytes(thr, buf, (duk_size_t) len);
39701 duk_push_lstring(ctx, (const char *) buf, (duk_size_t) len);
39702 } else {
39703 p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len); /* zero for paranoia */
39704 DUK_ASSERT(p != NULL);
39705 duk_debug_read_bytes(thr, p, (duk_size_t) len);
39706 (void) duk_buffer_to_string(ctx, -1); /* Safety relies on debug client, which is OK. */
39707 }
39708
39709 return duk_require_hstring(ctx, -1);
39710}
39711
39712DUK_INTERNAL duk_hstring *duk_debug_read_hstring(duk_hthread *thr) {
39713 duk_context *ctx = (duk_context *) thr;
39714 duk_small_uint_t x;
39715 duk_uint32_t len;
39716
39717 DUK_ASSERT(thr != NULL);
39718
39719 x = duk_debug_read_byte(thr);
39720 if (x >= 0x60 && x <= 0x7f) {
39721 /* For short strings, use a fixed temp buffer. */
39722 len = (duk_uint32_t) (x - 0x60);
39723 } else if (x == DUK_DBG_IB_STR2) {
39724 len = (duk_uint32_t) duk__debug_read_uint16_raw(thr);
39725 } else if (x == DUK_DBG_IB_STR4) {
39726 len = (duk_uint32_t) duk__debug_read_uint32_raw(thr);
39727 } else {
39728 goto fail;
39729 }
39730
39731 return duk__debug_read_hstring_raw(thr, len);
39732
39733 fail:
39734 DUK_D(DUK_DPRINT("debug connection error: failed to decode int"));
39735 DUK__SET_CONN_BROKEN(thr, 1);
39736 duk_push_hstring_empty(ctx); /* always push some string */
39737 return duk_require_hstring(ctx, -1);
39738}
39739
39740DUK_LOCAL duk_hbuffer *duk__debug_read_hbuffer_raw(duk_hthread *thr, duk_uint32_t len) {
39741 duk_context *ctx = (duk_context *) thr;
39742 duk_uint8_t *p;
39743
39744 p = (duk_uint8_t *) duk_push_fixed_buffer(ctx, (duk_size_t) len); /* zero for paranoia */
39745 DUK_ASSERT(p != NULL);
39746 duk_debug_read_bytes(thr, p, (duk_size_t) len);
39747
39748 return duk_require_hbuffer(ctx, -1);
39749}
39750
39751DUK_LOCAL void *duk__debug_read_pointer_raw(duk_hthread *thr) {
39752 duk_small_uint_t x;
39753 duk__ptr_union pu;
39754
39755 DUK_ASSERT(thr != NULL);
39756
39757 x = duk_debug_read_byte(thr);
39758 if (x != sizeof(pu)) {
39759 goto fail;
39760 }
39761 duk_debug_read_bytes(thr, (duk_uint8_t *) &pu.p, sizeof(pu));
39762#if defined(DUK_USE_INTEGER_LE)
39763 duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu));
39764#endif
39765 return (void *) pu.p;
39766
39767 fail:
39768 DUK_D(DUK_DPRINT("debug connection error: failed to decode pointer"));
39769 DUK__SET_CONN_BROKEN(thr, 1);
39770 return (void *) NULL;
39771}
39772
39773DUK_LOCAL duk_double_t duk__debug_read_double_raw(duk_hthread *thr) {
39775
39776 DUK_ASSERT(sizeof(du.uc) == 8);
39777 duk_debug_read_bytes(thr, (duk_uint8_t *) du.uc, sizeof(du.uc));
39778 DUK_DBLUNION_DOUBLE_NTOH(&du);
39779 return du.d;
39780}
39781
39782#if 0
39783DUK_INTERNAL duk_heaphdr *duk_debug_read_heapptr(duk_hthread *thr) {
39784 duk_small_uint_t x;
39785
39786 DUK_ASSERT(thr != NULL);
39787
39788 x = duk_debug_read_byte(thr);
39789 if (x != DUK_DBG_IB_HEAPPTR) {
39790 goto fail;
39791 }
39792
39793 return (duk_heaphdr *) duk__debug_read_pointer_raw(thr);
39794
39795 fail:
39796 DUK_D(DUK_DPRINT("debug connection error: failed to decode heapptr"));
39797 DUK__SET_CONN_BROKEN(thr, 1);
39798 return NULL;
39799}
39800#endif
39801
39802DUK_INTERNAL duk_heaphdr *duk_debug_read_any_ptr(duk_hthread *thr) {
39803 duk_small_uint_t x;
39804
39805 DUK_ASSERT(thr != NULL);
39806
39807 x = duk_debug_read_byte(thr);
39808 switch (x) {
39809 case DUK_DBG_IB_OBJECT:
39810 case DUK_DBG_IB_POINTER:
39811 case DUK_DBG_IB_HEAPPTR:
39812 /* Accept any pointer-like value; for 'object' dvalue, read
39813 * and ignore the class number.
39814 */
39815 if (x == DUK_DBG_IB_OBJECT) {
39816 duk_debug_skip_byte(thr);
39817 }
39818 break;
39819 default:
39820 goto fail;
39821 }
39822
39823 return (duk_heaphdr *) duk__debug_read_pointer_raw(thr);
39824
39825 fail:
39826 DUK_D(DUK_DPRINT("debug connection error: failed to decode any pointer (object, pointer, heapptr)"));
39827 DUK__SET_CONN_BROKEN(thr, 1);
39828 return NULL;
39829}
39830
39831DUK_INTERNAL duk_tval *duk_debug_read_tval(duk_hthread *thr) {
39832 duk_context *ctx = (duk_context *) thr;
39833 duk_uint8_t x;
39834 duk_uint_t t;
39835 duk_uint32_t len;
39836
39837 DUK_ASSERT(thr != NULL);
39838
39839 x = duk_debug_read_byte(thr);
39840
39841 if (x >= 0xc0) {
39842 t = (duk_uint_t) (x - 0xc0);
39843 t = (t << 8) + duk_debug_read_byte(thr);
39844 duk_push_uint(ctx, (duk_uint_t) t);
39845 goto return_ptr;
39846 }
39847 if (x >= 0x80) {
39848 duk_push_uint(ctx, (duk_uint_t) (x - 0x80));
39849 goto return_ptr;
39850 }
39851 if (x >= 0x60) {
39852 len = (duk_uint32_t) (x - 0x60);
39853 duk__debug_read_hstring_raw(thr, len);
39854 goto return_ptr;
39855 }
39856
39857 switch (x) {
39858 case DUK_DBG_IB_INT4: {
39859 duk_int32_t i = duk__debug_read_int32_raw(thr);
39860 duk_push_i32(ctx, i);
39861 break;
39862 }
39863 case DUK_DBG_IB_STR4: {
39864 len = duk__debug_read_uint32_raw(thr);
39865 duk__debug_read_hstring_raw(thr, len);
39866 break;
39867 }
39868 case DUK_DBG_IB_STR2: {
39869 len = duk__debug_read_uint16_raw(thr);
39870 duk__debug_read_hstring_raw(thr, len);
39871 break;
39872 }
39873 case DUK_DBG_IB_BUF4: {
39874 len = duk__debug_read_uint32_raw(thr);
39875 duk__debug_read_hbuffer_raw(thr, len);
39876 break;
39877 }
39878 case DUK_DBG_IB_BUF2: {
39879 len = duk__debug_read_uint16_raw(thr);
39880 duk__debug_read_hbuffer_raw(thr, len);
39881 break;
39882 }
39883 case DUK_DBG_IB_UNDEFINED: {
39884 duk_push_undefined(ctx);
39885 break;
39886 }
39887 case DUK_DBG_IB_NULL: {
39888 duk_push_null(ctx);
39889 break;
39890 }
39891 case DUK_DBG_IB_TRUE: {
39892 duk_push_true(ctx);
39893 break;
39894 }
39895 case DUK_DBG_IB_FALSE: {
39896 duk_push_false(ctx);
39897 break;
39898 }
39899 case DUK_DBG_IB_NUMBER: {
39900 duk_double_t d;
39901 d = duk__debug_read_double_raw(thr);
39902 duk_push_number(ctx, d);
39903 break;
39904 }
39905 case DUK_DBG_IB_OBJECT: {
39906 duk_heaphdr *h;
39907 duk_debug_skip_byte(thr);
39908 h = (duk_heaphdr *) duk__debug_read_pointer_raw(thr);
39909 duk_push_heapptr(thr, (void *) h);
39910 break;
39911 }
39912 case DUK_DBG_IB_POINTER: {
39913 void *ptr;
39914 ptr = duk__debug_read_pointer_raw(thr);
39915 duk_push_pointer(thr, ptr);
39916 break;
39917 }
39918 case DUK_DBG_IB_LIGHTFUNC: {
39919 /* XXX: Not needed for now, so not implemented. Note that
39920 * function pointers may have different size/layout than
39921 * a void pointer.
39922 */
39923 DUK_D(DUK_DPRINT("reading lightfunc values unimplemented"));
39924 goto fail;
39925 }
39926 case DUK_DBG_IB_HEAPPTR: {
39927 duk_heaphdr *h;
39928 h = (duk_heaphdr *) duk__debug_read_pointer_raw(thr);
39929 duk_push_heapptr(thr, (void *) h);
39930 break;
39931 }
39932 case DUK_DBG_IB_UNUSED: /* unused: not accepted in inbound messages */
39933 default:
39934 goto fail;
39935 }
39936
39937 return_ptr:
39938 return DUK_GET_TVAL_NEGIDX(thr, -1);
39939
39940 fail:
39941 DUK_D(DUK_DPRINT("debug connection error: failed to decode tval"));
39942 DUK__SET_CONN_BROKEN(thr, 1);
39943 return NULL;
39944}
39945
39946/*
39947 * Debug connection write primitives
39948 */
39949
39950/* Write fully. */
39951DUK_INTERNAL void duk_debug_write_bytes(duk_hthread *thr, const duk_uint8_t *data, duk_size_t length) {
39952 duk_heap *heap;
39953 const duk_uint8_t *p;
39954 duk_size_t left;
39955 duk_size_t got;
39956
39957 DUK_ASSERT(thr != NULL);
39958 DUK_ASSERT(length == 0 || data != NULL);
39959 heap = thr->heap;
39960 DUK_ASSERT(heap != NULL);
39961
39962 if (heap->dbg_write_cb == NULL) {
39963 DUK_D(DUK_DPRINT("attempt to write %ld bytes in detached state, ignore", (long) length));
39964 return;
39965 }
39966 if (length == 0) {
39967 /* Avoid doing an actual write callback with length == 0,
39968 * because that's reserved for a write flush.
39969 */
39970 return;
39971 }
39972 DUK_ASSERT(data != NULL);
39973
39974 p = data;
39975 for (;;) {
39976 left = (duk_size_t) ((data + length) - p);
39977 if (left == 0) {
39978 break;
39979 }
39980 DUK_ASSERT(heap->dbg_write_cb != NULL);
39981 DUK_ASSERT(left >= 1);
39982#if defined(DUK_USE_DEBUGGER_TRANSPORT_TORTURE)
39983 left = 1;
39984#endif
39985 got = heap->dbg_write_cb(heap->dbg_udata, (const char *) p, left);
39986 if (got == 0 || got > left) {
39987 duk__debug_null_most_callbacks(thr); /* avoid calling write callback in detach1() */
39988 DUK_D(DUK_DPRINT("connection error during write"));
39989 DUK__SET_CONN_BROKEN(thr, 1);
39990 return;
39991 }
39992 p += got;
39993 }
39994}
39995
39996DUK_INTERNAL void duk_debug_write_byte(duk_hthread *thr, duk_uint8_t x) {
39997 duk_debug_write_bytes(thr, (const duk_uint8_t *) &x, 1);
39998}
39999
40000DUK_INTERNAL void duk_debug_write_unused(duk_hthread *thr) {
40001 duk_debug_write_byte(thr, DUK_DBG_IB_UNUSED);
40002}
40003
40004DUK_INTERNAL void duk_debug_write_undefined(duk_hthread *thr) {
40005 duk_debug_write_byte(thr, DUK_DBG_IB_UNDEFINED);
40006}
40007
40008#if defined(DUK_USE_DEBUGGER_INSPECT)
40009DUK_INTERNAL void duk_debug_write_null(duk_hthread *thr) {
40010 duk_debug_write_byte(thr, DUK_DBG_IB_NULL);
40011}
40012#endif
40013
40014DUK_INTERNAL void duk_debug_write_boolean(duk_hthread *thr, duk_uint_t val) {
40015 duk_debug_write_byte(thr, val ? DUK_DBG_IB_TRUE : DUK_DBG_IB_FALSE);
40016}
40017
40018/* Write signed 32-bit integer. */
40019DUK_INTERNAL void duk_debug_write_int(duk_hthread *thr, duk_int32_t x) {
40020 duk_uint8_t buf[5];
40021 duk_size_t len;
40022
40023 DUK_ASSERT(thr != NULL);
40024
40025 if (x >= 0 && x <= 0x3fL) {
40026 buf[0] = (duk_uint8_t) (0x80 + x);
40027 len = 1;
40028 } else if (x >= 0 && x <= 0x3fffL) {
40029 buf[0] = (duk_uint8_t) (0xc0 + (x >> 8));
40030 buf[1] = (duk_uint8_t) (x & 0xff);
40031 len = 2;
40032 } else {
40033 /* Signed integers always map to 4 bytes now. */
40034 buf[0] = (duk_uint8_t) DUK_DBG_IB_INT4;
40035 buf[1] = (duk_uint8_t) ((x >> 24) & 0xff);
40036 buf[2] = (duk_uint8_t) ((x >> 16) & 0xff);
40037 buf[3] = (duk_uint8_t) ((x >> 8) & 0xff);
40038 buf[4] = (duk_uint8_t) (x & 0xff);
40039 len = 5;
40040 }
40041 duk_debug_write_bytes(thr, buf, len);
40042}
40043
40044/* Write unsigned 32-bit integer. */
40045DUK_INTERNAL void duk_debug_write_uint(duk_hthread *thr, duk_uint32_t x) {
40046 /* The debugger protocol doesn't support a plain integer encoding for
40047 * the full 32-bit unsigned range (only 32-bit signed). For now,
40048 * unsigned 32-bit values simply written as signed ones. This is not
40049 * a concrete issue except for 32-bit heaphdr fields. Proper solutions
40050 * would be to (a) write such integers as IEEE doubles or (b) add an
40051 * unsigned 32-bit dvalue.
40052 */
40053 if (x >= 0x80000000UL) {
40054 DUK_D(DUK_DPRINT("writing unsigned integer 0x%08lx as signed integer",
40055 (long) x));
40056 }
40057 duk_debug_write_int(thr, (duk_int32_t) x);
40058}
40059
40060DUK_INTERNAL void duk_debug_write_strbuf(duk_hthread *thr, const char *data, duk_size_t length, duk_uint8_t marker_base) {
40061 duk_uint8_t buf[5];
40062 duk_size_t buflen;
40063
40064 DUK_ASSERT(thr != NULL);
40065 DUK_ASSERT(length == 0 || data != NULL);
40066
40067 if (length <= 0x1fUL && marker_base == DUK_DBG_IB_STR4) {
40068 /* For strings, special form for short lengths. */
40069 buf[0] = (duk_uint8_t) (0x60 + length);
40070 buflen = 1;
40071 } else if (length <= 0xffffUL) {
40072 buf[0] = (duk_uint8_t) (marker_base + 1);
40073 buf[1] = (duk_uint8_t) (length >> 8);
40074 buf[2] = (duk_uint8_t) (length & 0xff);
40075 buflen = 3;
40076 } else {
40077 buf[0] = (duk_uint8_t) marker_base;
40078 buf[1] = (duk_uint8_t) (length >> 24);
40079 buf[2] = (duk_uint8_t) ((length >> 16) & 0xff);
40080 buf[3] = (duk_uint8_t) ((length >> 8) & 0xff);
40081 buf[4] = (duk_uint8_t) (length & 0xff);
40082 buflen = 5;
40083 }
40084
40085 duk_debug_write_bytes(thr, (const duk_uint8_t *) buf, buflen);
40086 duk_debug_write_bytes(thr, (const duk_uint8_t *) data, length);
40087}
40088
40089DUK_INTERNAL void duk_debug_write_string(duk_hthread *thr, const char *data, duk_size_t length) {
40090 duk_debug_write_strbuf(thr, data, length, DUK_DBG_IB_STR4);
40091}
40092
40093DUK_INTERNAL void duk_debug_write_cstring(duk_hthread *thr, const char *data) {
40094 DUK_ASSERT(thr != NULL);
40095
40096 duk_debug_write_string(thr,
40097 data,
40098 data ? DUK_STRLEN(data) : 0);
40099}
40100
40101DUK_INTERNAL void duk_debug_write_hstring(duk_hthread *thr, duk_hstring *h) {
40102 DUK_ASSERT(thr != NULL);
40103
40104 /* XXX: differentiate null pointer from empty string? */
40105 duk_debug_write_string(thr,
40106 (h != NULL ? (const char *) DUK_HSTRING_GET_DATA(h) : NULL),
40107 (h != NULL ? (duk_size_t) DUK_HSTRING_GET_BYTELEN(h) : 0));
40108}
40109
40110DUK_LOCAL void duk__debug_write_hstring_safe_top(duk_hthread *thr) {
40111 duk_context *ctx = (duk_context *) thr;
40112 duk_debug_write_hstring(thr, duk_safe_to_hstring(ctx, -1));
40113}
40114
40115DUK_INTERNAL void duk_debug_write_buffer(duk_hthread *thr, const char *data, duk_size_t length) {
40116 duk_debug_write_strbuf(thr, data, length, DUK_DBG_IB_BUF4);
40117}
40118
40119DUK_INTERNAL void duk_debug_write_hbuffer(duk_hthread *thr, duk_hbuffer *h) {
40120 DUK_ASSERT(thr != NULL);
40121
40122 duk_debug_write_buffer(thr,
40123 (h != NULL ? (const char *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h) : NULL),
40124 (h != NULL ? (duk_size_t) DUK_HBUFFER_GET_SIZE(h) : 0));
40125}
40126
40127DUK_LOCAL void duk__debug_write_pointer_raw(duk_hthread *thr, void *ptr, duk_uint8_t ibyte) {
40128 duk_uint8_t buf[2];
40129 duk__ptr_union pu;
40130
40131 DUK_ASSERT(thr != NULL);
40132 DUK_ASSERT(sizeof(ptr) >= 1 && sizeof(ptr) <= 16);
40133 /* ptr may be NULL */
40134
40135 buf[0] = ibyte;
40136 buf[1] = sizeof(pu);
40137 duk_debug_write_bytes(thr, buf, 2);
40138 pu.p = (void *) ptr;
40139#if defined(DUK_USE_INTEGER_LE)
40140 duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu));
40141#endif
40142 duk_debug_write_bytes(thr, (const duk_uint8_t *) &pu.p, (duk_size_t) sizeof(pu));
40143}
40144
40145DUK_INTERNAL void duk_debug_write_pointer(duk_hthread *thr, void *ptr) {
40146 duk__debug_write_pointer_raw(thr, ptr, DUK_DBG_IB_POINTER);
40147}
40148
40149#if defined(DUK_USE_DEBUGGER_DUMPHEAP) || defined(DUK_USE_DEBUGGER_INSPECT)
40150DUK_INTERNAL void duk_debug_write_heapptr(duk_hthread *thr, duk_heaphdr *h) {
40151 duk__debug_write_pointer_raw(thr, (void *) h, DUK_DBG_IB_HEAPPTR);
40152}
40153#endif /* DUK_USE_DEBUGGER_DUMPHEAP || DUK_USE_DEBUGGER_INSPECT */
40154
40155DUK_INTERNAL void duk_debug_write_hobject(duk_hthread *thr, duk_hobject *obj) {
40156 duk_uint8_t buf[3];
40157 duk__ptr_union pu;
40158
40159 DUK_ASSERT(thr != NULL);
40160 DUK_ASSERT(sizeof(obj) >= 1 && sizeof(obj) <= 16);
40161 DUK_ASSERT(obj != NULL);
40162
40163 buf[0] = DUK_DBG_IB_OBJECT;
40164 buf[1] = (duk_uint8_t) DUK_HOBJECT_GET_CLASS_NUMBER(obj);
40165 buf[2] = sizeof(pu);
40166 duk_debug_write_bytes(thr, buf, 3);
40167 pu.p = (void *) obj;
40168#if defined(DUK_USE_INTEGER_LE)
40169 duk_byteswap_bytes((duk_uint8_t *) pu.b, sizeof(pu));
40170#endif
40171 duk_debug_write_bytes(thr, (const duk_uint8_t *) &pu.p, (duk_size_t) sizeof(pu));
40172}
40173
40174DUK_INTERNAL void duk_debug_write_tval(duk_hthread *thr, duk_tval *tv) {
40175 duk_c_function lf_func;
40176 duk_small_uint_t lf_flags;
40177 duk_uint8_t buf[4];
40178 duk_double_union du1;
40179 duk_double_union du2;
40180 duk_int32_t i32;
40181
40182 DUK_ASSERT(thr != NULL);
40183 DUK_ASSERT(tv != NULL);
40184
40185 switch (DUK_TVAL_GET_TAG(tv)) {
40186 case DUK_TAG_UNDEFINED:
40187 duk_debug_write_byte(thr, DUK_DBG_IB_UNDEFINED);
40188 break;
40189 case DUK_TAG_UNUSED:
40190 duk_debug_write_byte(thr, DUK_DBG_IB_UNUSED);
40191 break;
40192 case DUK_TAG_NULL:
40193 duk_debug_write_byte(thr, DUK_DBG_IB_NULL);
40194 break;
40195 case DUK_TAG_BOOLEAN:
40196 DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv) == 0 ||
40197 DUK_TVAL_GET_BOOLEAN(tv) == 1);
40198 duk_debug_write_boolean(thr, DUK_TVAL_GET_BOOLEAN(tv));
40199 break;
40200 case DUK_TAG_POINTER:
40201 duk_debug_write_pointer(thr, (void *) DUK_TVAL_GET_POINTER(tv));
40202 break;
40203 case DUK_TAG_LIGHTFUNC:
40204 DUK_TVAL_GET_LIGHTFUNC(tv, lf_func, lf_flags);
40205 buf[0] = DUK_DBG_IB_LIGHTFUNC;
40206 buf[1] = (duk_uint8_t) (lf_flags >> 8);
40207 buf[2] = (duk_uint8_t) (lf_flags & 0xff);
40208 buf[3] = sizeof(lf_func);
40209 duk_debug_write_bytes(thr, buf, 4);
40210 duk_debug_write_bytes(thr, (const duk_uint8_t *) &lf_func, sizeof(lf_func));
40211 break;
40212 case DUK_TAG_STRING:
40213 duk_debug_write_hstring(thr, DUK_TVAL_GET_STRING(tv));
40214 break;
40215 case DUK_TAG_OBJECT:
40216 duk_debug_write_hobject(thr, DUK_TVAL_GET_OBJECT(tv));
40217 break;
40218 case DUK_TAG_BUFFER:
40219 duk_debug_write_hbuffer(thr, DUK_TVAL_GET_BUFFER(tv));
40220 break;
40221#if defined(DUK_USE_FASTINT)
40222 case DUK_TAG_FASTINT:
40223#endif
40224 default:
40225 /* Numbers are normalized to big (network) endian. We can
40226 * (but are not required) to use integer dvalues when there's
40227 * no loss of precision.
40228 *
40229 * XXX: share check with other code; this check is slow but
40230 * reliable and doesn't require careful exponent/mantissa
40231 * mask tricks as in the fastint downgrade code.
40232 */
40233 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
40234 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
40235 du1.d = DUK_TVAL_GET_NUMBER(tv);
40236 i32 = (duk_int32_t) du1.d;
40237 du2.d = (duk_double_t) i32;
40238
40239 DUK_DD(DUK_DDPRINT("i32=%ld du1=%02x%02x%02x%02x%02x%02x%02x%02x "
40240 "du2=%02x%02x%02x%02x%02x%02x%02x%02x",
40241 (long) i32,
40242 (unsigned int) du1.uc[0], (unsigned int) du1.uc[1],
40243 (unsigned int) du1.uc[2], (unsigned int) du1.uc[3],
40244 (unsigned int) du1.uc[4], (unsigned int) du1.uc[5],
40245 (unsigned int) du1.uc[6], (unsigned int) du1.uc[7],
40246 (unsigned int) du2.uc[0], (unsigned int) du2.uc[1],
40247 (unsigned int) du2.uc[2], (unsigned int) du2.uc[3],
40248 (unsigned int) du2.uc[4], (unsigned int) du2.uc[5],
40249 (unsigned int) du2.uc[6], (unsigned int) du2.uc[7]));
40250
40251 if (DUK_MEMCMP((const void *) du1.uc, (const void *) du2.uc, sizeof(du1.uc)) == 0) {
40252 duk_debug_write_int(thr, i32);
40253 } else {
40254 DUK_DBLUNION_DOUBLE_HTON(&du1);
40255 duk_debug_write_byte(thr, DUK_DBG_IB_NUMBER);
40256 duk_debug_write_bytes(thr, (const duk_uint8_t *) du1.uc, sizeof(du1.uc));
40257 }
40258 }
40259}
40260
40261#if defined(DUK_USE_DEBUGGER_DUMPHEAP)
40262/* Variant for writing duk_tvals so that any heap allocated values are
40263 * written out as tagged heap pointers.
40264 */
40265DUK_LOCAL void duk__debug_write_tval_heapptr(duk_hthread *thr, duk_tval *tv) {
40266 if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
40267 duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
40268 duk_debug_write_heapptr(thr, h);
40269 } else {
40270 duk_debug_write_tval(thr, tv);
40271 }
40272}
40273#endif /* DUK_USE_DEBUGGER_DUMPHEAP */
40274
40275/*
40276 * Debug connection message write helpers
40277 */
40278
40279#if 0 /* unused */
40280DUK_INTERNAL void duk_debug_write_request(duk_hthread *thr, duk_small_uint_t command) {
40281 duk_debug_write_byte(thr, DUK_DBG_IB_REQUEST);
40282 duk_debug_write_int(thr, command);
40283}
40284#endif
40285
40286DUK_INTERNAL void duk_debug_write_reply(duk_hthread *thr) {
40287 duk_debug_write_byte(thr, DUK_DBG_IB_REPLY);
40288}
40289
40290DUK_INTERNAL void duk_debug_write_error_eom(duk_hthread *thr, duk_small_uint_t err_code, const char *msg) {
40291 /* Allow NULL 'msg' */
40292 duk_debug_write_byte(thr, DUK_DBG_IB_ERROR);
40293 duk_debug_write_int(thr, (duk_int32_t) err_code);
40294 duk_debug_write_cstring(thr, msg);
40295 duk_debug_write_eom(thr);
40296}
40297
40298DUK_INTERNAL void duk_debug_write_notify(duk_hthread *thr, duk_small_uint_t command) {
40299 duk_debug_write_byte(thr, DUK_DBG_IB_NOTIFY);
40300 duk_debug_write_int(thr, command);
40301}
40302
40303DUK_INTERNAL void duk_debug_write_eom(duk_hthread *thr) {
40304 duk_debug_write_byte(thr, DUK_DBG_IB_EOM);
40305
40306 /* As an initial implementation, write flush after every EOM (and the
40307 * version identifier). A better implementation would flush only when
40308 * Duktape is finished processing messages so that a flush only happens
40309 * after all outbound messages are finished on that occasion.
40310 */
40311 duk_debug_write_flush(thr);
40312}
40313
40314/*
40315 * Status message and helpers
40316 */
40317
40318DUK_INTERNAL duk_uint_fast32_t duk_debug_curr_line(duk_hthread *thr) {
40319 duk_context *ctx = (duk_context *) thr;
40320 duk_activation *act;
40321 duk_uint_fast32_t line;
40322 duk_uint_fast32_t pc;
40323
40324 act = duk_hthread_get_current_activation(thr); /* may be NULL */
40325 if (act == NULL) {
40326 return 0;
40327 }
40328
40329 /* We're conceptually between two opcodes; act->pc indicates the next
40330 * instruction to be executed. This is usually the correct pc/line to
40331 * indicate in Status. (For the 'debugger' statement this now reports
40332 * the pc/line after the debugger statement because the debugger opcode
40333 * has already been executed.)
40334 */
40335
40336 pc = duk_hthread_get_act_curr_pc(thr, act);
40337
40338 /* XXX: this should be optimized to be a raw query and avoid valstack
40339 * operations if possible.
40340 */
40341 duk_push_tval(ctx, &act->tv_func);
40342 line = duk_hobject_pc2line_query(ctx, -1, pc);
40343 duk_pop(ctx);
40344 return line;
40345}
40346
40347DUK_INTERNAL void duk_debug_send_status(duk_hthread *thr) {
40348 duk_context *ctx = (duk_context *) thr;
40349 duk_activation *act;
40350
40351 duk_debug_write_notify(thr, DUK_DBG_CMD_STATUS);
40352 duk_debug_write_int(thr, (DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) ? 1 : 0));
40353
40354 DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* unsigned */
40355 if (thr->callstack_top == 0) {
40356 duk_debug_write_undefined(thr);
40357 duk_debug_write_undefined(thr);
40358 duk_debug_write_int(thr, 0);
40359 duk_debug_write_int(thr, 0);
40360 } else {
40361 act = thr->callstack + thr->callstack_top - 1;
40362 duk_push_tval(ctx, &act->tv_func);
40363 duk_get_prop_string(ctx, -1, "fileName");
40364 duk__debug_write_hstring_safe_top(thr);
40365 duk_get_prop_string(ctx, -2, "name");
40366 duk__debug_write_hstring_safe_top(thr);
40367 duk_pop_3(ctx);
40368 /* Report next pc/line to be executed. */
40369 duk_debug_write_uint(thr, (duk_uint32_t) duk_debug_curr_line(thr));
40370 duk_debug_write_uint(thr, (duk_uint32_t) duk_hthread_get_act_curr_pc(thr, act));
40371 }
40372
40373 duk_debug_write_eom(thr);
40374}
40375
40376#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY)
40377DUK_INTERNAL void duk_debug_send_throw(duk_hthread *thr, duk_bool_t fatal) {
40378 /*
40379 * NFY <int: 5> <int: fatal> <str: msg> <str: filename> <int: linenumber> EOM
40380 */
40381
40382 duk_context *ctx = (duk_context *) thr;
40383 duk_activation *act;
40384 duk_uint32_t pc;
40385
40386 DUK_ASSERT(thr->valstack_top > thr->valstack); /* At least: ... [err] */
40387
40388 duk_debug_write_notify(thr, DUK_DBG_CMD_THROW);
40389 duk_debug_write_int(thr, fatal);
40390
40391 /* Report thrown value to client coerced to string */
40392 duk_dup_top(ctx);
40393 duk__debug_write_hstring_safe_top(thr);
40394 duk_pop(ctx);
40395
40396 if (duk_is_error(ctx, -1)) {
40397 /* Error instance, use augmented error data directly */
40398 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_FILE_NAME);
40399 duk__debug_write_hstring_safe_top(thr);
40400 duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_LINE_NUMBER);
40401 duk_debug_write_uint(thr, duk_get_uint(ctx, -1));
40402 } else {
40403 /* For anything other than an Error instance, we calculate the error
40404 * location directly from the current activation.
40405 */
40406 act = thr->callstack + thr->callstack_top - 1;
40407 duk_push_tval(ctx, &act->tv_func);
40408 duk_get_prop_string(ctx, -1, "fileName");
40409 duk__debug_write_hstring_safe_top(thr);
40410 pc = duk_hthread_get_act_prev_pc(thr, act);
40411 duk_debug_write_uint(thr, (duk_uint32_t) duk_hobject_pc2line_query(ctx, -2, pc));
40412 }
40413 duk_pop_2(ctx); /* shared pop */
40414
40415 duk_debug_write_eom(thr);
40416}
40417#endif /* DUK_USE_DEBUGGER_THROW_NOTIFY */
40418
40419/*
40420 * Debug message processing
40421 */
40422
40423/* Skip dvalue. */
40424DUK_LOCAL duk_bool_t duk__debug_skip_dvalue(duk_hthread *thr) {
40425 duk_uint8_t x;
40426 duk_uint32_t len;
40427
40428 x = duk_debug_read_byte(thr);
40429
40430 if (x >= 0xc0) {
40431 duk_debug_skip_byte(thr);
40432 return 0;
40433 }
40434 if (x >= 0x80) {
40435 return 0;
40436 }
40437 if (x >= 0x60) {
40438 duk_debug_skip_bytes(thr, x - 0x60);
40439 return 0;
40440 }
40441 switch(x) {
40442 case DUK_DBG_IB_EOM:
40443 return 1; /* Return 1: got EOM */
40444 case DUK_DBG_IB_REQUEST:
40445 case DUK_DBG_IB_REPLY:
40446 case DUK_DBG_IB_ERROR:
40447 case DUK_DBG_IB_NOTIFY:
40448 break;
40449 case DUK_DBG_IB_INT4:
40450 (void) duk__debug_read_uint32_raw(thr);
40451 break;
40452 case DUK_DBG_IB_STR4:
40453 case DUK_DBG_IB_BUF4:
40454 len = duk__debug_read_uint32_raw(thr);
40455 duk_debug_skip_bytes(thr, len);
40456 break;
40457 case DUK_DBG_IB_STR2:
40458 case DUK_DBG_IB_BUF2:
40459 len = duk__debug_read_uint16_raw(thr);
40460 duk_debug_skip_bytes(thr, len);
40461 break;
40462 case DUK_DBG_IB_UNUSED:
40463 case DUK_DBG_IB_UNDEFINED:
40464 case DUK_DBG_IB_NULL:
40465 case DUK_DBG_IB_TRUE:
40466 case DUK_DBG_IB_FALSE:
40467 break;
40468 case DUK_DBG_IB_NUMBER:
40469 duk_debug_skip_bytes(thr, 8);
40470 break;
40471 case DUK_DBG_IB_OBJECT:
40472 duk_debug_skip_byte(thr);
40473 len = duk_debug_read_byte(thr);
40474 duk_debug_skip_bytes(thr, len);
40475 break;
40476 case DUK_DBG_IB_POINTER:
40477 case DUK_DBG_IB_HEAPPTR:
40478 len = duk_debug_read_byte(thr);
40479 duk_debug_skip_bytes(thr, len);
40480 break;
40481 case DUK_DBG_IB_LIGHTFUNC:
40482 duk_debug_skip_bytes(thr, 2);
40483 len = duk_debug_read_byte(thr);
40484 duk_debug_skip_bytes(thr, len);
40485 break;
40486 default:
40487 goto fail;
40488 }
40489
40490 return 0;
40491
40492 fail:
40493 DUK__SET_CONN_BROKEN(thr, 1);
40494 return 1; /* Pretend like we got EOM */
40495}
40496
40497/* Skip dvalues to EOM. */
40498DUK_LOCAL void duk__debug_skip_to_eom(duk_hthread *thr) {
40499 for (;;) {
40500 if (duk__debug_skip_dvalue(thr)) {
40501 break;
40502 }
40503 }
40504}
40505
40506DUK_LOCAL duk_int32_t duk__debug_read_validate_csindex(duk_hthread *thr) {
40507 duk_int32_t level;
40508 level = duk_debug_read_int(thr);
40509 if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
40510 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack index");
40511 return 0; /* zero indicates failure */
40512 }
40513 return level;
40514}
40515
40516/*
40517 * Simple commands
40518 */
40519
40520DUK_LOCAL void duk__debug_handle_basic_info(duk_hthread *thr, duk_heap *heap) {
40521 DUK_UNREF(heap);
40522 DUK_D(DUK_DPRINT("debug command Version"));
40523
40524 duk_debug_write_reply(thr);
40525 duk_debug_write_int(thr, DUK_VERSION);
40526 duk_debug_write_cstring(thr, DUK_GIT_DESCRIBE);
40527 duk_debug_write_cstring(thr, DUK_USE_TARGET_INFO);
40528#if defined(DUK_USE_DOUBLE_LE)
40529 duk_debug_write_int(thr, 1);
40530#elif defined(DUK_USE_DOUBLE_ME)
40531 duk_debug_write_int(thr, 2);
40532#elif defined(DUK_USE_DOUBLE_BE)
40533 duk_debug_write_int(thr, 3);
40534#else
40535 duk_debug_write_int(thr, 0);
40536#endif
40537 duk_debug_write_int(thr, (duk_int_t) sizeof(void *));
40538 duk_debug_write_eom(thr);
40539}
40540
40541DUK_LOCAL void duk__debug_handle_trigger_status(duk_hthread *thr, duk_heap *heap) {
40542 DUK_UNREF(heap);
40543 DUK_D(DUK_DPRINT("debug command TriggerStatus"));
40544
40545 duk_debug_write_reply(thr);
40546 duk_debug_write_eom(thr);
40547 heap->dbg_state_dirty = 1;
40548}
40549
40550DUK_LOCAL void duk__debug_handle_pause(duk_hthread *thr, duk_heap *heap) {
40551 DUK_D(DUK_DPRINT("debug command Pause"));
40552
40553 DUK_HEAP_SET_PAUSED(heap);
40554 duk_debug_write_reply(thr);
40555 duk_debug_write_eom(thr);
40556}
40557
40558DUK_LOCAL void duk__debug_handle_resume(duk_hthread *thr, duk_heap *heap) {
40559 DUK_D(DUK_DPRINT("debug command Resume"));
40560
40561 DUK_HEAP_CLEAR_PAUSED(heap);
40562 duk_debug_write_reply(thr);
40563 duk_debug_write_eom(thr);
40564}
40565
40566DUK_LOCAL void duk__debug_handle_step(duk_hthread *thr, duk_heap *heap, duk_int32_t cmd) {
40567 duk_small_uint_t step_type;
40568 duk_uint_fast32_t line;
40569
40570 DUK_D(DUK_DPRINT("debug command StepInto/StepOver/StepOut: %d", (int) cmd));
40571
40572 if (cmd == DUK_DBG_CMD_STEPINTO) {
40573 step_type = DUK_STEP_TYPE_INTO;
40574 } else if (cmd == DUK_DBG_CMD_STEPOVER) {
40575 step_type = DUK_STEP_TYPE_OVER;
40576 } else {
40577 DUK_ASSERT(cmd == DUK_DBG_CMD_STEPOUT);
40578 step_type = DUK_STEP_TYPE_OUT;
40579 }
40580
40581 line = duk_debug_curr_line(thr);
40582 if (line > 0) {
40583 DUK_HEAP_CLEAR_DEBUGGER_PAUSED(heap);
40584 heap->dbg_step_type = step_type;
40585 heap->dbg_step_thread = thr;
40586 heap->dbg_step_csindex = thr->callstack_top - 1;
40587 heap->dbg_step_startline = line;
40588 heap->dbg_state_dirty = 1;
40589 } else {
40590 DUK_D(DUK_DPRINT("cannot determine current line, stepinto/stepover/stepout ignored"));
40591 }
40592 duk_debug_write_reply(thr);
40593 duk_debug_write_eom(thr);
40594}
40595
40596DUK_LOCAL void duk__debug_handle_list_break(duk_hthread *thr, duk_heap *heap) {
40597 duk_small_int_t i;
40598
40599 DUK_D(DUK_DPRINT("debug command ListBreak"));
40600 duk_debug_write_reply(thr);
40601 for (i = 0; i < (duk_small_int_t) heap->dbg_breakpoint_count; i++) {
40602 duk_debug_write_hstring(thr, heap->dbg_breakpoints[i].filename);
40603 duk_debug_write_uint(thr, (duk_uint32_t) heap->dbg_breakpoints[i].line);
40604 }
40605 duk_debug_write_eom(thr);
40606}
40607
40608DUK_LOCAL void duk__debug_handle_add_break(duk_hthread *thr, duk_heap *heap) {
40609 duk_hstring *filename;
40610 duk_uint32_t linenumber;
40611 duk_small_int_t idx;
40612
40613 DUK_UNREF(heap);
40614
40615 filename = duk_debug_read_hstring(thr);
40616 linenumber = (duk_uint32_t) duk_debug_read_int(thr);
40617 DUK_D(DUK_DPRINT("debug command AddBreak: %!O:%ld", (duk_hobject *) filename, (long) linenumber));
40618 idx = duk_debug_add_breakpoint(thr, filename, linenumber);
40619 if (idx >= 0) {
40620 duk_debug_write_reply(thr);
40621 duk_debug_write_int(thr, (duk_int32_t) idx);
40622 duk_debug_write_eom(thr);
40623 } else {
40624 duk_debug_write_error_eom(thr, DUK_DBG_ERR_TOOMANY, "no space for breakpoint");
40625 }
40626}
40627
40628DUK_LOCAL void duk__debug_handle_del_break(duk_hthread *thr, duk_heap *heap) {
40629 duk_small_uint_t idx;
40630
40631 DUK_UNREF(heap);
40632
40633 DUK_D(DUK_DPRINT("debug command DelBreak"));
40634 idx = (duk_small_uint_t) duk_debug_read_int(thr);
40635 if (duk_debug_remove_breakpoint(thr, idx)) {
40636 duk_debug_write_reply(thr);
40637 duk_debug_write_eom(thr);
40638 } else {
40639 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid breakpoint index");
40640 }
40641}
40642
40643DUK_LOCAL void duk__debug_handle_get_var(duk_hthread *thr, duk_heap *heap) {
40644 duk_context *ctx = (duk_context *) thr;
40645 duk_hstring *str;
40646 duk_bool_t rc;
40647 duk_int32_t level;
40648
40649 DUK_UNREF(heap);
40650 DUK_D(DUK_DPRINT("debug command GetVar"));
40651
40652 level = duk__debug_read_validate_csindex(thr);
40653 if (level == 0) {
40654 return;
40655 }
40656 str = duk_debug_read_hstring(thr); /* push to stack */
40657 DUK_ASSERT(str != NULL);
40658
40659 if (thr->callstack_top > 0) {
40660 rc = duk_js_getvar_activation(thr,
40661 thr->callstack + thr->callstack_top + level,
40662 str,
40663 0);
40664 } else {
40665 /* No activation, no variable access. Could also pretend
40666 * we're in the global program context and read stuff off
40667 * the global object.
40668 */
40669 DUK_D(DUK_DPRINT("callstack empty, no activation -> ignore getvar"));
40670 rc = 0;
40671 }
40672
40673 duk_debug_write_reply(thr);
40674 if (rc) {
40675 duk_debug_write_int(thr, 1);
40676 DUK_ASSERT(duk_get_tval(ctx, -2) != NULL);
40677 duk_debug_write_tval(thr, duk_get_tval(ctx, -2));
40678 } else {
40679 duk_debug_write_int(thr, 0);
40680 duk_debug_write_unused(thr);
40681 }
40682 duk_debug_write_eom(thr);
40683}
40684
40685DUK_LOCAL void duk__debug_handle_put_var(duk_hthread *thr, duk_heap *heap) {
40686 duk_hstring *str;
40687 duk_tval *tv;
40688 duk_int32_t level;
40689
40690 DUK_UNREF(heap);
40691 DUK_D(DUK_DPRINT("debug command PutVar"));
40692
40693 level = duk__debug_read_validate_csindex(thr);
40694 if (level == 0) {
40695 return;
40696 }
40697 str = duk_debug_read_hstring(thr); /* push to stack */
40698 DUK_ASSERT(str != NULL);
40699 tv = duk_debug_read_tval(thr);
40700 if (tv == NULL) {
40701 /* detached */
40702 return;
40703 }
40704
40705 if (thr->callstack_top > 0) {
40706 duk_js_putvar_activation(thr,
40707 thr->callstack + thr->callstack_top + level,
40708 str,
40709 tv,
40710 0);
40711 } else {
40712 DUK_D(DUK_DPRINT("callstack empty, no activation -> ignore putvar"));
40713 }
40714
40715 /* XXX: Current putvar implementation doesn't have a success flag,
40716 * add one and send to debug client?
40717 */
40718 duk_debug_write_reply(thr);
40719 duk_debug_write_eom(thr);
40720}
40721
40722DUK_LOCAL void duk__debug_handle_get_call_stack(duk_hthread *thr, duk_heap *heap) {
40723 duk_context *ctx = (duk_context *) thr;
40724 duk_hthread *curr_thr = thr;
40725 duk_activation *curr_act;
40726 duk_uint_fast32_t pc;
40727 duk_uint_fast32_t line;
40728 duk_size_t i;
40729
40730 DUK_ASSERT(thr != NULL);
40731 DUK_UNREF(heap);
40732
40733 duk_debug_write_reply(thr);
40734 while (curr_thr != NULL) {
40735 i = curr_thr->callstack_top;
40736 while (i > 0) {
40737 i--;
40738 curr_act = curr_thr->callstack + i;
40739
40740 /* PC/line semantics here are:
40741 * - For callstack top we're conceptually between two
40742 * opcodes and current PC indicates next line to
40743 * execute, so report that (matches Status).
40744 * - For other activations we're conceptually still
40745 * executing the instruction at PC-1, so report that
40746 * (matches error stacktrace behavior).
40747 * - See: https://github.com/svaarala/duktape/issues/281
40748 */
40749
40750 /* XXX: optimize to use direct reads, i.e. avoid
40751 * value stack operations.
40752 */
40753 duk_push_tval(ctx, &curr_act->tv_func);
40754 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_FILE_NAME);
40755 duk__debug_write_hstring_safe_top(thr);
40756 duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_NAME);
40757 duk__debug_write_hstring_safe_top(thr);
40758 pc = duk_hthread_get_act_curr_pc(thr, curr_act);
40759 if (i != curr_thr->callstack_top - 1 && pc > 0) {
40760 pc--;
40761 }
40762 line = duk_hobject_pc2line_query(ctx, -3, pc);
40763 duk_debug_write_uint(thr, (duk_uint32_t) line);
40764 duk_debug_write_uint(thr, (duk_uint32_t) pc);
40765 duk_pop_3(ctx);
40766 }
40767 curr_thr = curr_thr->resumer;
40768 }
40769 /* SCANBUILD: warning about 'thr' potentially being NULL here,
40770 * warning is incorrect because thr != NULL always here.
40771 */
40772 duk_debug_write_eom(thr);
40773}
40774
40775DUK_LOCAL void duk__debug_handle_get_locals(duk_hthread *thr, duk_heap *heap) {
40776 duk_context *ctx = (duk_context *) thr;
40777 duk_activation *curr_act;
40778 duk_int32_t level;
40779 duk_hstring *varname;
40780
40781 DUK_UNREF(heap);
40782
40783 level = duk__debug_read_validate_csindex(thr);
40784 if (level == 0) {
40785 return;
40786 }
40787 duk_debug_write_reply(thr);
40788
40789 curr_act = thr->callstack + thr->callstack_top + level;
40790
40791 /* XXX: several nice-to-have improvements here:
40792 * - Use direct reads avoiding value stack operations
40793 * - Avoid triggering getters, indicate getter values to debug client
40794 * - If side effects are possible, add error catching
40795 */
40796
40797 duk_push_tval(ctx, &curr_act->tv_func);
40798 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_VARMAP);
40799 if (duk_is_object(ctx, -1)) {
40800 duk_enum(ctx, -1, 0 /*enum_flags*/);
40801 while (duk_next(ctx, -1 /*enum_index*/, 0 /*get_value*/)) {
40802 varname = duk_known_hstring(ctx, -1);
40803
40804 duk_js_getvar_activation(thr, curr_act, varname, 0 /*throw_flag*/);
40805 /* [ ... func varmap enum key value this ] */
40806 duk_debug_write_hstring(thr, duk_get_hstring(ctx, -3));
40807 duk_debug_write_tval(thr, duk_get_tval(ctx, -2));
40808 duk_pop_3(ctx); /* -> [ ... func varmap enum ] */
40809 }
40810 } else {
40811 DUK_D(DUK_DPRINT("varmap is not an object in GetLocals, ignore"));
40812 }
40813
40814 duk_debug_write_eom(thr);
40815}
40816
40817DUK_LOCAL void duk__debug_handle_eval(duk_hthread *thr, duk_heap *heap) {
40818 duk_context *ctx = (duk_context *) thr;
40819 duk_small_uint_t call_flags;
40820 duk_int_t call_ret;
40821 duk_small_int_t eval_err;
40822 duk_int_t num_eval_args;
40823 duk_bool_t direct_eval;
40824 duk_int32_t level;
40825
40826 DUK_UNREF(heap);
40827
40828 DUK_D(DUK_DPRINT("debug command Eval"));
40829
40830 /* The eval code is executed within the lexical environment of a specified
40831 * activation. For now, use global object eval() function, with the eval
40832 * considered a 'direct call to eval'.
40833 *
40834 * Callstack index for debug commands only affects scope -- the callstack
40835 * as seen by, e.g. Duktape.act() will be the same regardless.
40836 */
40837
40838 /* nargs == 2 so we can pass a callstack index to eval(). */
40839 duk_push_c_function(ctx, duk_bi_global_object_eval, 2 /*nargs*/);
40840 duk_push_undefined(ctx); /* 'this' binding shouldn't matter here */
40841
40842 /* Read callstack index, if non-null. */
40843 if (duk_debug_peek_byte(thr) == DUK_DBG_IB_NULL) {
40844 direct_eval = 0;
40845 (void) duk_debug_read_byte(thr);
40846 } else {
40847 direct_eval = 1;
40848 level = duk__debug_read_validate_csindex(thr);
40849 if (level == 0) {
40850 return;
40851 }
40852 }
40853
40854 DUK_ASSERT(!direct_eval ||
40855 (level < 0 && -level <= (duk_int32_t) thr->callstack_top));
40856
40857 (void) duk_debug_read_hstring(thr);
40858 if (direct_eval) {
40859 num_eval_args = 2;
40860 duk_push_int(ctx, level - 1); /* compensate for eval() call */
40861 } else {
40862 num_eval_args = 1;
40863 }
40864
40865 /* [ ... eval "eval" eval_input level ] */
40866
40867 call_flags = 0;
40868 if (direct_eval && thr->callstack_top >= (duk_size_t) -level) {
40869 duk_activation *act;
40870 duk_hobject *fun;
40871
40872 act = thr->callstack + thr->callstack_top + level;
40873 fun = DUK_ACT_GET_FUNC(act);
40874 if (fun != NULL && DUK_HOBJECT_IS_COMPFUNC(fun)) {
40875 /* Direct eval requires that there's a current
40876 * activation and it is an Ecmascript function.
40877 * When Eval is executed from e.g. cooperate API
40878 * call we'll need to do an indirect eval instead.
40879 */
40880 call_flags |= DUK_CALL_FLAG_DIRECT_EVAL;
40881 }
40882 }
40883
40884 call_ret = duk_handle_call_protected(thr, num_eval_args, call_flags);
40885
40886 if (call_ret == DUK_EXEC_SUCCESS) {
40887 eval_err = 0;
40888 /* Use result value as is. */
40889 } else {
40890 /* For errors a string coerced result is most informative
40891 * right now, as the debug client doesn't have the capability
40892 * to traverse the error object.
40893 */
40894 eval_err = 1;
40895 duk_safe_to_string(ctx, -1);
40896 }
40897
40898 /* [ ... result ] */
40899
40900 duk_debug_write_reply(thr);
40901 duk_debug_write_int(thr, (duk_int32_t) eval_err);
40902 DUK_ASSERT(duk_get_tval(ctx, -1) != NULL);
40903 duk_debug_write_tval(thr, duk_get_tval(ctx, -1));
40904 duk_debug_write_eom(thr);
40905}
40906
40907DUK_LOCAL void duk__debug_handle_detach(duk_hthread *thr, duk_heap *heap) {
40908 DUK_UNREF(heap);
40909 DUK_D(DUK_DPRINT("debug command Detach"));
40910
40911 duk_debug_write_reply(thr);
40912 duk_debug_write_eom(thr);
40913
40914 DUK_D(DUK_DPRINT("debug connection detached, mark broken"));
40915 DUK__SET_CONN_BROKEN(thr, 0); /* not an error */
40916}
40917
40918DUK_LOCAL void duk__debug_handle_apprequest(duk_hthread *thr, duk_heap *heap) {
40919 duk_context *ctx = (duk_context *) thr;
40920 duk_idx_t old_top;
40921
40922 DUK_D(DUK_DPRINT("debug command AppRequest"));
40923
40924 old_top = duk_get_top(ctx); /* save stack top */
40925
40926 if (heap->dbg_request_cb != NULL) {
40927 duk_idx_t nrets;
40928 duk_idx_t nvalues = 0;
40929 duk_idx_t top, idx;
40930
40931 /* Read tvals from the message and push them onto the valstack,
40932 * then call the request callback to process the request.
40933 */
40934 while (duk_debug_peek_byte(thr) != DUK_DBG_IB_EOM) {
40935 duk_tval *tv;
40936 if (!duk_check_stack(ctx, 1)) {
40937 DUK_D(DUK_DPRINT("failed to allocate space for request dvalue(s)"));
40938 goto fail;
40939 }
40940 tv = duk_debug_read_tval(thr); /* push to stack */
40941 if (tv == NULL) {
40942 /* detached */
40943 return;
40944 }
40945 nvalues++;
40946 }
40947 DUK_ASSERT(duk_get_top(ctx) == old_top + nvalues);
40948
40949 /* Request callback should push values for reply to client onto valstack */
40950 DUK_D(DUK_DPRINT("calling into AppRequest request_cb with nvalues=%ld, old_top=%ld, top=%ld",
40951 (long) nvalues, (long) old_top, (long) duk_get_top(ctx)));
40952 nrets = heap->dbg_request_cb(ctx, heap->dbg_udata, nvalues);
40953 DUK_D(DUK_DPRINT("returned from AppRequest request_cb; nvalues=%ld -> nrets=%ld, old_top=%ld, top=%ld",
40954 (long) nvalues, (long) nrets, (long) old_top, (long) duk_get_top(ctx)));
40955 if (nrets >= 0) {
40956 DUK_ASSERT(duk_get_top(ctx) >= old_top + nrets);
40957 if (duk_get_top(ctx) < old_top + nrets) {
40958 DUK_D(DUK_DPRINT("AppRequest callback doesn't match value stack configuration, "
40959 "top=%ld < old_top=%ld + nrets=%ld; "
40960 "this might mean it's unsafe to continue!",
40961 (long) duk_get_top(ctx), (long) old_top, (long) nrets));
40962 goto fail;
40963 }
40964
40965 /* Reply with tvals pushed by request callback */
40966 duk_debug_write_byte(thr, DUK_DBG_IB_REPLY);
40967 top = duk_get_top(ctx);
40968 for (idx = top - nrets; idx < top; idx++) {
40969 duk_debug_write_tval(thr, DUK_GET_TVAL_POSIDX(ctx, idx));
40970 }
40971 duk_debug_write_eom(thr);
40972 } else {
40973 DUK_ASSERT(duk_get_top(ctx) >= old_top + 1);
40974 if (duk_get_top(ctx) < old_top + 1) {
40975 DUK_D(DUK_DPRINT("request callback return value doesn't match value stack configuration"));
40976 goto fail;
40977 }
40978 duk_debug_write_error_eom(thr, DUK_DBG_ERR_APPLICATION, duk_get_string(ctx, -1));
40979 }
40980
40981 duk_set_top(ctx, old_top); /* restore stack top */
40982 } else {
40983 DUK_D(DUK_DPRINT("no request callback, treat AppRequest as unsupported"));
40984 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNSUPPORTED, "AppRequest unsupported by target");
40985 }
40986
40987 return;
40988
40989 fail:
40990 duk_set_top(ctx, old_top); /* restore stack top */
40991 DUK__SET_CONN_BROKEN(thr, 1);
40992}
40993
40994/*
40995 * DumpHeap command
40996 */
40997
40998#if defined(DUK_USE_DEBUGGER_DUMPHEAP)
40999/* XXX: this has some overlap with object inspection; remove this and make
41000 * DumpHeap return lists of heapptrs instead?
41001 */
41002DUK_LOCAL void duk__debug_dump_heaphdr(duk_hthread *thr, duk_heap *heap, duk_heaphdr *hdr) {
41003 DUK_UNREF(heap);
41004
41005 duk_debug_write_heapptr(thr, hdr);
41006 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HEAPHDR_GET_TYPE(hdr));
41007 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HEAPHDR_GET_FLAGS_RAW(hdr));
41008#if defined(DUK_USE_REFERENCE_COUNTING)
41009 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HEAPHDR_GET_REFCOUNT(hdr));
41010#else
41011 duk_debug_write_int(thr, (duk_int32_t) -1);
41012#endif
41013
41014 switch (DUK_HEAPHDR_GET_TYPE(hdr)) {
41015 case DUK_HTYPE_STRING: {
41016 duk_hstring *h = (duk_hstring *) hdr;
41017
41018 duk_debug_write_uint(thr, (duk_int32_t) DUK_HSTRING_GET_BYTELEN(h));
41019 duk_debug_write_uint(thr, (duk_int32_t) DUK_HSTRING_GET_CHARLEN(h));
41020 duk_debug_write_uint(thr, (duk_int32_t) DUK_HSTRING_GET_HASH(h));
41021 duk_debug_write_hstring(thr, h);
41022 break;
41023 }
41024 case DUK_HTYPE_OBJECT: {
41025 duk_hobject *h = (duk_hobject *) hdr;
41026 duk_hstring *k;
41027 duk_uint_fast32_t i;
41028
41029 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_CLASS_NUMBER(h));
41030 duk_debug_write_heapptr(thr, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(heap, h));
41031 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_ESIZE(h));
41032 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_ENEXT(h));
41033 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_ASIZE(h));
41034 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_GET_HSIZE(h));
41035
41036 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
41037 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HOBJECT_E_GET_FLAGS(heap, h, i));
41038 k = DUK_HOBJECT_E_GET_KEY(heap, h, i);
41039 duk_debug_write_heapptr(thr, (duk_heaphdr *) k);
41040 if (k == NULL) {
41041 duk_debug_write_int(thr, 0); /* isAccessor */
41042 duk_debug_write_unused(thr);
41043 continue;
41044 }
41045 if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, h, i)) {
41046 duk_debug_write_int(thr, 1); /* isAccessor */
41047 duk_debug_write_heapptr(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.get);
41048 duk_debug_write_heapptr(thr, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.set);
41049 } else {
41050 duk_debug_write_int(thr, 0); /* isAccessor */
41051
41052 duk__debug_write_tval_heapptr(thr, &DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->v);
41053 }
41054 }
41055
41056 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
41057 /* Note: array dump will include elements beyond
41058 * 'length'.
41059 */
41060 duk__debug_write_tval_heapptr(thr, DUK_HOBJECT_A_GET_VALUE_PTR(heap, h, i));
41061 }
41062 break;
41063 }
41064 case DUK_HTYPE_BUFFER: {
41065 duk_hbuffer *h = (duk_hbuffer *) hdr;
41066
41067 duk_debug_write_uint(thr, (duk_uint32_t) DUK_HBUFFER_GET_SIZE(h));
41068 duk_debug_write_buffer(thr, (const char *) DUK_HBUFFER_GET_DATA_PTR(heap, h), (duk_size_t) DUK_HBUFFER_GET_SIZE(h));
41069 break;
41070 }
41071 default: {
41072 DUK_D(DUK_DPRINT("invalid htype: %d", (int) DUK_HEAPHDR_GET_TYPE(hdr)));
41073 }
41074 }
41075}
41076
41077DUK_LOCAL void duk__debug_dump_heap_allocated(duk_hthread *thr, duk_heap *heap) {
41078 duk_heaphdr *hdr;
41079
41080 hdr = heap->heap_allocated;
41081 while (hdr != NULL) {
41082 duk__debug_dump_heaphdr(thr, heap, hdr);
41083 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
41084 }
41085}
41086
41087#if defined(DUK_USE_STRTAB_CHAIN)
41088DUK_LOCAL void duk__debug_dump_strtab_chain(duk_hthread *thr, duk_heap *heap) {
41089 duk_uint_fast32_t i, j;
41091#if defined(DUK_USE_HEAPPTR16)
41092 duk_uint16_t *lst;
41093#else
41094 duk_hstring **lst;
41095#endif
41096 duk_hstring *h;
41097
41098 for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
41099 e = heap->strtable + i;
41100 if (e->listlen > 0) {
41101#if defined(DUK_USE_HEAPPTR16)
41102 lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
41103#else
41104 lst = e->u.strlist;
41105#endif
41106 DUK_ASSERT(lst != NULL);
41107
41108 for (j = 0; j < e->listlen; j++) {
41109#if defined(DUK_USE_HEAPPTR16)
41110 h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[j]);
41111#else
41112 h = lst[j];
41113#endif
41114 if (h != NULL) {
41115 duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h);
41116 }
41117 }
41118 } else {
41119#if defined(DUK_USE_HEAPPTR16)
41120 h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16);
41121#else
41122 h = e->u.str;
41123#endif
41124 if (h != NULL) {
41125 duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h);
41126 }
41127 }
41128 }
41129}
41130#endif /* DUK_USE_STRTAB_CHAIN */
41131
41132#if defined(DUK_USE_STRTAB_PROBE)
41133DUK_LOCAL void duk__debug_dump_strtab_probe(duk_hthread *thr, duk_heap *heap) {
41134 duk_uint32_t i;
41135 duk_hstring *h;
41136
41137 for (i = 0; i < heap->st_size; i++) {
41138#if defined(DUK_USE_HEAPPTR16)
41139 h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]);
41140#else
41141 h = heap->strtable[i];
41142#endif
41143 if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) {
41144 continue;
41145 }
41146
41147 duk__debug_dump_heaphdr(thr, heap, (duk_heaphdr *) h);
41148 }
41149}
41150#endif /* DUK_USE_STRTAB_PROBE */
41151
41152DUK_LOCAL void duk__debug_handle_dump_heap(duk_hthread *thr, duk_heap *heap) {
41153 DUK_D(DUK_DPRINT("debug command DumpHeap"));
41154
41155 duk_debug_write_reply(thr);
41156 duk__debug_dump_heap_allocated(thr, heap);
41157#if defined(DUK_USE_STRTAB_CHAIN)
41158 duk__debug_dump_strtab_chain(thr, heap);
41159#endif
41160#if defined(DUK_USE_STRTAB_PROBE)
41161 duk__debug_dump_strtab_probe(thr, heap);
41162#endif
41163 duk_debug_write_eom(thr);
41164}
41165#endif /* DUK_USE_DEBUGGER_DUMPHEAP */
41166
41167DUK_LOCAL void duk__debug_handle_get_bytecode(duk_hthread *thr, duk_heap *heap) {
41168 duk_activation *act;
41169 duk_hcompfunc *fun = NULL;
41170 duk_size_t i, n;
41171 duk_tval *tv;
41172 duk_hobject **fn;
41173 duk_int32_t level = -1;
41174 duk_uint8_t ibyte;
41175
41176 DUK_UNREF(heap);
41177
41178 DUK_D(DUK_DPRINT("debug command GetBytecode"));
41179
41180 ibyte = duk_debug_peek_byte(thr);
41181 if (ibyte != DUK_DBG_IB_EOM) {
41182 tv = duk_debug_read_tval(thr);
41183 if (tv == NULL) {
41184 /* detached */
41185 return;
41186 }
41187 if (DUK_TVAL_IS_OBJECT(tv)) {
41188 /* tentative, checked later */
41189 fun = (duk_hcompfunc *) DUK_TVAL_GET_OBJECT(tv);
41190 DUK_ASSERT(fun != NULL);
41191 } else if (DUK_TVAL_IS_NUMBER(tv)) {
41192 level = (duk_int32_t) DUK_TVAL_GET_NUMBER(tv);
41193 } else {
41194 DUK_D(DUK_DPRINT("invalid argument to GetBytecode: %!T", tv));
41195 goto fail_args;
41196 }
41197 }
41198
41199 if (fun == NULL) {
41200 if (level >= 0 || -level > (duk_int32_t) thr->callstack_top) {
41201 DUK_D(DUK_DPRINT("invalid callstack index for GetBytecode"));
41202 goto fail_index;
41203 }
41204 act = thr->callstack + thr->callstack_top + level;
41205 fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
41206 }
41207
41208 if (fun == NULL || !DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) fun)) {
41209 DUK_D(DUK_DPRINT("invalid argument to GetBytecode: %!O", fun));
41210 goto fail_args;
41211 }
41212 DUK_ASSERT(fun != NULL && DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) fun));
41213
41214 duk_debug_write_reply(thr);
41215 n = DUK_HCOMPFUNC_GET_CONSTS_COUNT(heap, fun);
41216 duk_debug_write_int(thr, (duk_int32_t) n);
41217 tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(heap, fun);
41218 for (i = 0; i < n; i++) {
41219 duk_debug_write_tval(thr, tv);
41220 tv++;
41221 }
41222 n = DUK_HCOMPFUNC_GET_FUNCS_COUNT(heap, fun);
41223 duk_debug_write_int(thr, (duk_int32_t) n);
41224 fn = DUK_HCOMPFUNC_GET_FUNCS_BASE(heap, fun);
41225 for (i = 0; i < n; i++) {
41226 duk_debug_write_hobject(thr, *fn);
41227 fn++;
41228 }
41229 duk_debug_write_string(thr,
41230 (const char *) DUK_HCOMPFUNC_GET_CODE_BASE(heap, fun),
41231 (duk_size_t) DUK_HCOMPFUNC_GET_CODE_SIZE(heap, fun));
41232 duk_debug_write_eom(thr);
41233 return;
41234
41235 fail_args:
41236 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid argument");
41237 return;
41238
41239 fail_index:
41240 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "invalid callstack index");
41241 return;
41242}
41243
41244/*
41245 * Object inspection commands: GetHeapObjInfo, GetObjPropDesc,
41246 * GetObjPropDescRange
41247 */
41248
41249#if defined(DUK_USE_DEBUGGER_INSPECT)
41250
41251#if 0 /* pruned */
41252DUK_LOCAL const char * const duk__debug_getinfo_heaphdr_keys[] = {
41253 "reachable",
41254 "temproot",
41255 "finalizable",
41256 "finalized",
41257 "readonly"
41258 /* NULL not needed here */
41259};
41260DUK_LOCAL duk_uint_t duk__debug_getinfo_heaphdr_masks[] = {
41261 DUK_HEAPHDR_FLAG_REACHABLE,
41262 DUK_HEAPHDR_FLAG_TEMPROOT,
41263 DUK_HEAPHDR_FLAG_FINALIZABLE,
41264 DUK_HEAPHDR_FLAG_FINALIZED,
41265 DUK_HEAPHDR_FLAG_READONLY,
41266 0 /* terminator */
41267};
41268#endif
41269DUK_LOCAL const char * const duk__debug_getinfo_hstring_keys[] = {
41270#if 0
41271 "arridx",
41272 "symbol",
41273 "hidden",
41274 "reserved_word",
41275 "strict_reserved_word",
41276 "eval_or_arguments",
41277#endif
41278 "extdata"
41279 /* NULL not needed here */
41280};
41281DUK_LOCAL duk_uint_t duk__debug_getinfo_hstring_masks[] = {
41282#if 0
41283 DUK_HSTRING_FLAG_ARRIDX,
41284 DUK_HSTRING_FLAG_SYMBOL,
41285 DUK_HSTRING_FLAG_HIDDEN,
41286 DUK_HSTRING_FLAG_RESERVED_WORD,
41287 DUK_HSTRING_FLAG_STRICT_RESERVED_WORD,
41288 DUK_HSTRING_FLAG_EVAL_OR_ARGUMENTS,
41289#endif
41290 DUK_HSTRING_FLAG_EXTDATA,
41291 0 /* terminator */
41292};
41293DUK_LOCAL const char * const duk__debug_getinfo_hobject_keys[] = {
41294 "extensible",
41295 "constructable",
41296 "boundfunc",
41297 "compfunc",
41298 "natfunc",
41299 "bufobj",
41300 "thread",
41301 "array_part",
41302 "strict",
41303 "notail",
41304 "newenv",
41305 "namebinding",
41306 "createargs",
41307 "envrecclosed",
41308 "exotic_array",
41309 "exotic_stringobj",
41310 "exotic_arguments",
41311 "exotic_dukfunc",
41312 "exotic_proxyobj"
41313 /* NULL not needed here */
41314};
41315DUK_LOCAL duk_uint_t duk__debug_getinfo_hobject_masks[] = {
41316 DUK_HOBJECT_FLAG_EXTENSIBLE,
41317 DUK_HOBJECT_FLAG_CONSTRUCTABLE,
41318 DUK_HOBJECT_FLAG_BOUNDFUNC,
41319 DUK_HOBJECT_FLAG_COMPFUNC,
41320 DUK_HOBJECT_FLAG_NATFUNC,
41321 DUK_HOBJECT_FLAG_BUFOBJ,
41322 DUK_HOBJECT_FLAG_THREAD,
41323 DUK_HOBJECT_FLAG_ARRAY_PART,
41324 DUK_HOBJECT_FLAG_STRICT,
41325 DUK_HOBJECT_FLAG_NOTAIL,
41326 DUK_HOBJECT_FLAG_NEWENV,
41327 DUK_HOBJECT_FLAG_NAMEBINDING,
41328 DUK_HOBJECT_FLAG_CREATEARGS,
41329 DUK_HOBJECT_FLAG_ENVRECCLOSED,
41330 DUK_HOBJECT_FLAG_EXOTIC_ARRAY,
41331 DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ,
41332 DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS,
41333 DUK_HOBJECT_FLAG_EXOTIC_DUKFUNC,
41334 DUK_HOBJECT_FLAG_EXOTIC_PROXYOBJ,
41335 0 /* terminator */
41336};
41337DUK_LOCAL const char * const duk__debug_getinfo_hbuffer_keys[] = {
41338 "dynamic",
41339 "external"
41340 /* NULL not needed here */
41341};
41342DUK_LOCAL duk_uint_t duk__debug_getinfo_hbuffer_masks[] = {
41343 DUK_HBUFFER_FLAG_DYNAMIC,
41344 DUK_HBUFFER_FLAG_EXTERNAL,
41345 0 /* terminator */
41346};
41347
41348DUK_LOCAL void duk__debug_getinfo_flags_key(duk_hthread *thr, const char *key) {
41349 duk_debug_write_uint(thr, 0);
41350 duk_debug_write_cstring(thr, key);
41351}
41352
41353DUK_LOCAL void duk__debug_getinfo_prop_uint(duk_hthread *thr, const char *key, duk_uint_t val) {
41354 duk_debug_write_uint(thr, 0);
41355 duk_debug_write_cstring(thr, key);
41356 duk_debug_write_uint(thr, val);
41357}
41358
41359DUK_LOCAL void duk__debug_getinfo_prop_int(duk_hthread *thr, const char *key, duk_int_t val) {
41360 duk_debug_write_uint(thr, 0);
41361 duk_debug_write_cstring(thr, key);
41362 duk_debug_write_int(thr, val);
41363}
41364
41365DUK_LOCAL void duk__debug_getinfo_prop_bool(duk_hthread *thr, const char *key, duk_bool_t val) {
41366 duk_debug_write_uint(thr, 0);
41367 duk_debug_write_cstring(thr, key);
41368 duk_debug_write_boolean(thr, val);
41369}
41370
41371DUK_LOCAL void duk__debug_getinfo_bitmask(duk_hthread *thr, const char * const * keys, duk_uint_t *masks, duk_uint_t flags) {
41372 const char *key;
41373 duk_uint_t mask;
41374
41375 for (;;) {
41376 mask = *masks++;
41377 if (!mask) {
41378 break;
41379 }
41380 key = *keys++;
41381 DUK_ASSERT(key != NULL);
41382
41383 DUK_DD(DUK_DDPRINT("inspect bitmask: key=%s, mask=0x%08lx, flags=0x%08lx", key, (unsigned long) mask, (unsigned long) flags));
41384 duk__debug_getinfo_prop_bool(thr, key, flags & mask);
41385 }
41386}
41387
41388/* Inspect a property using a virtual index into a conceptual property list
41389 * consisting of (1) all array part items from [0,a_size[ (even when above
41390 * .length) and (2) all entry part items from [0,e_next[. Unused slots are
41391 * indicated using dvalue 'unused'.
41392 */
41393DUK_LOCAL duk_bool_t duk__debug_getprop_index(duk_hthread *thr, duk_heap *heap, duk_hobject *h_obj, duk_uint_t idx) {
41394 duk_uint_t a_size;
41395 duk_tval *tv;
41396 duk_hstring *h_key;
41397 duk_hobject *h_getset;
41398 duk_uint_t flags;
41399
41400 DUK_UNREF(heap);
41401
41402 a_size = DUK_HOBJECT_GET_ASIZE(h_obj);
41403 if (idx < a_size) {
41404 duk_debug_write_uint(thr, DUK_PROPDESC_FLAGS_WEC);
41405 duk_debug_write_uint(thr, idx);
41406 tv = DUK_HOBJECT_A_GET_VALUE_PTR(heap, h_obj, idx);
41407 duk_debug_write_tval(thr, tv);
41408 return 1;
41409 }
41410
41411 idx -= a_size;
41412 if (idx >= DUK_HOBJECT_GET_ENEXT(h_obj)) {
41413 return 0;
41414 }
41415
41416 h_key = DUK_HOBJECT_E_GET_KEY(heap, h_obj, idx);
41417 if (h_key == NULL) {
41418 duk_debug_write_uint(thr, 0);
41419 duk_debug_write_null(thr);
41420 duk_debug_write_unused(thr);
41421 return 1;
41422 }
41423
41424 flags = DUK_HOBJECT_E_GET_FLAGS(heap, h_obj, idx);
41425 if (DUK_HSTRING_HAS_SYMBOL(h_key)) {
41426 flags |= DUK_DBG_PROPFLAG_SYMBOL;
41427 }
41428 if (DUK_HSTRING_HAS_HIDDEN(h_key)) {
41429 flags |= DUK_DBG_PROPFLAG_HIDDEN;
41430 }
41431 duk_debug_write_uint(thr, flags);
41432 duk_debug_write_hstring(thr, h_key);
41433 if (flags & DUK_PROPDESC_FLAG_ACCESSOR) {
41434 h_getset = DUK_HOBJECT_E_GET_VALUE_GETTER(heap, h_obj, idx);
41435 if (h_getset) {
41436 duk_debug_write_hobject(thr, h_getset);
41437 } else {
41438 duk_debug_write_null(thr);
41439 }
41440 h_getset = DUK_HOBJECT_E_GET_VALUE_SETTER(heap, h_obj, idx);
41441 if (h_getset) {
41442 duk_debug_write_hobject(thr, h_getset);
41443 } else {
41444 duk_debug_write_null(thr);
41445 }
41446 } else {
41447 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, h_obj, idx);
41448 duk_debug_write_tval(thr, tv);
41449 }
41450 return 1;
41451}
41452
41453DUK_LOCAL void duk__debug_handle_get_heap_obj_info(duk_hthread *thr, duk_heap *heap) {
41454 duk_heaphdr *h;
41455
41456 DUK_D(DUK_DPRINT("debug command GetHeapObjInfo"));
41457 DUK_UNREF(heap);
41458
41459 h = duk_debug_read_any_ptr(thr);
41460 if (!h) {
41461 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid target");
41462 return;
41463 }
41464
41465 duk_debug_write_reply(thr);
41466
41467 /* As with all inspection code, we rely on the debug client providing
41468 * a valid, non-stale pointer: there's no portable way to safely
41469 * validate the pointer here.
41470 */
41471
41472 duk__debug_getinfo_flags_key(thr, "heapptr");
41473 duk_debug_write_heapptr(thr, h);
41474
41475 /* XXX: comes out as signed now */
41476 duk__debug_getinfo_prop_uint(thr, "heaphdr_flags", (duk_uint_t) DUK_HEAPHDR_GET_FLAGS(h));
41477 duk__debug_getinfo_prop_uint(thr, "heaphdr_type", (duk_uint_t) DUK_HEAPHDR_GET_TYPE(h));
41478#if defined(DUK_USE_REFERENCE_COUNTING)
41479 duk__debug_getinfo_prop_uint(thr, "refcount", (duk_uint_t) DUK_HEAPHDR_GET_REFCOUNT(h));
41480#endif
41481#if 0 /* pruned */
41482 duk__debug_getinfo_bitmask(thr,
41483 duk__debug_getinfo_heaphdr_keys,
41484 duk__debug_getinfo_heaphdr_masks,
41485 DUK_HEAPHDR_GET_FLAGS_RAW(h));
41486#endif
41487
41488 switch (DUK_HEAPHDR_GET_TYPE(h)) {
41489 case DUK_HTYPE_STRING: {
41490 duk_hstring *h_str;
41491
41492 h_str = (duk_hstring *) h;
41493 duk__debug_getinfo_bitmask(thr,
41494 duk__debug_getinfo_hstring_keys,
41495 duk__debug_getinfo_hstring_masks,
41496 DUK_HEAPHDR_GET_FLAGS_RAW(h));
41497 duk__debug_getinfo_prop_uint(thr, "bytelen", DUK_HSTRING_GET_BYTELEN(h_str));
41498 duk__debug_getinfo_prop_uint(thr, "charlen", DUK_HSTRING_GET_CHARLEN(h_str));
41499 duk__debug_getinfo_prop_uint(thr, "hash", DUK_HSTRING_GET_HASH(h_str));
41500 duk__debug_getinfo_flags_key(thr, "data");
41501 duk_debug_write_hstring(thr, h_str);
41502 break;
41503 }
41504 case DUK_HTYPE_OBJECT: {
41505 duk_hobject *h_obj;
41506 duk_hobject *h_proto;
41507
41508 h_obj = (duk_hobject *) h;
41509 h_proto = DUK_HOBJECT_GET_PROTOTYPE(heap, h_obj);
41510
41511 /* duk_hobject specific fields. */
41512 duk__debug_getinfo_bitmask(thr,
41513 duk__debug_getinfo_hobject_keys,
41514 duk__debug_getinfo_hobject_masks,
41515 DUK_HEAPHDR_GET_FLAGS_RAW(h));
41516 duk__debug_getinfo_prop_uint(thr, "class_number", DUK_HOBJECT_GET_CLASS_NUMBER(h_obj));
41517 duk__debug_getinfo_flags_key(thr, "class_name");
41518 duk_debug_write_hstring(thr, DUK_HOBJECT_GET_CLASS_STRING(heap, h_obj));
41519 duk__debug_getinfo_flags_key(thr, "prototype");
41520 if (h_proto != NULL) {
41521 duk_debug_write_hobject(thr, h_proto);
41522 } else {
41523 duk_debug_write_null(thr);
41524 }
41525 duk__debug_getinfo_flags_key(thr, "props");
41526 duk_debug_write_pointer(thr, (void *) DUK_HOBJECT_GET_PROPS(heap, h_obj));
41527 duk__debug_getinfo_prop_uint(thr, "e_size", (duk_uint_t) DUK_HOBJECT_GET_ESIZE(h_obj));
41528 duk__debug_getinfo_prop_uint(thr, "e_next", (duk_uint_t) DUK_HOBJECT_GET_ENEXT(h_obj));
41529 duk__debug_getinfo_prop_uint(thr, "a_size", (duk_uint_t) DUK_HOBJECT_GET_ASIZE(h_obj));
41530 duk__debug_getinfo_prop_uint(thr, "h_size", (duk_uint_t) DUK_HOBJECT_GET_HSIZE(h_obj));
41531
41532 if (DUK_HOBJECT_IS_ARRAY(h_obj)) {
41533 duk_harray *h_arr;
41534 h_arr = (duk_harray *) h_obj;
41535
41536 duk__debug_getinfo_prop_int(thr, "length", h_arr->length);
41537 duk__debug_getinfo_prop_bool(thr, "length_nonwritable", h_arr->length_nonwritable);
41538 }
41539
41540 if (DUK_HOBJECT_IS_NATFUNC(h_obj)) {
41541 duk_hnatfunc *h_fun;
41542 h_fun = (duk_hnatfunc *) h_obj;
41543
41544 duk__debug_getinfo_prop_int(thr, "nargs", h_fun->nargs);
41545 duk__debug_getinfo_prop_int(thr, "magic", h_fun->magic);
41546 duk__debug_getinfo_prop_bool(thr, "varargs", h_fun->magic == DUK_HNATFUNC_NARGS_VARARGS);
41547 /* Native function pointer may be different from a void pointer,
41548 * and we serialize it from memory directly now (no byte swapping etc).
41549 */
41550 duk__debug_getinfo_flags_key(thr, "funcptr");
41551 duk_debug_write_buffer(thr, (const char *) &h_fun->func, sizeof(h_fun->func));
41552 }
41553
41554 if (DUK_HOBJECT_IS_COMPFUNC(h_obj)) {
41555 duk_hcompfunc *h_fun;
41556 duk_hbuffer *h_buf;
41557 duk_hobject *h_lexenv;
41558 duk_hobject *h_varenv;
41559 h_fun = (duk_hcompfunc *) h_obj;
41560
41561 duk__debug_getinfo_prop_int(thr, "nregs", h_fun->nregs);
41562 duk__debug_getinfo_prop_int(thr, "nargs", h_fun->nargs);
41563
41564 duk__debug_getinfo_flags_key(thr, "lex_env");
41565 h_lexenv = DUK_HCOMPFUNC_GET_LEXENV(thr->heap, h_fun);
41566 if (h_lexenv != NULL) {
41567 duk_debug_write_hobject(thr, h_lexenv);
41568 } else {
41569 duk_debug_write_null(thr);
41570 }
41571 duk__debug_getinfo_flags_key(thr, "var_env");
41572 h_varenv = DUK_HCOMPFUNC_GET_VARENV(thr->heap, h_fun);
41573 if (h_varenv != NULL) {
41574 duk_debug_write_hobject(thr, h_varenv);
41575 } else {
41576 duk_debug_write_null(thr);
41577 }
41578
41579 duk__debug_getinfo_prop_uint(thr, "start_line", h_fun->start_line);
41580 duk__debug_getinfo_prop_uint(thr, "end_line", h_fun->end_line);
41581 h_buf = (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(thr->heap, h_fun);
41582 if (h_buf != NULL) {
41583 duk__debug_getinfo_flags_key(thr, "data");
41584 duk_debug_write_heapptr(thr, (duk_heaphdr *) h_buf);
41585 }
41586 }
41587
41588 if (DUK_HOBJECT_IS_THREAD(h_obj)) {
41589 /* XXX: Currently no inspection of threads, e.g. value stack, call
41590 * stack, catch stack, etc.
41591 */
41592 duk_hthread *h_thr;
41593 h_thr = (duk_hthread *) h_obj;
41594 DUK_UNREF(h_thr);
41595 }
41596
41597#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
41598 if (DUK_HOBJECT_IS_BUFOBJ(h_obj)) {
41599 duk_hbufobj *h_bufobj;
41600 h_bufobj = (duk_hbufobj *) h_obj;
41601
41602 duk__debug_getinfo_prop_uint(thr, "slice_offset", h_bufobj->offset);
41603 duk__debug_getinfo_prop_uint(thr, "slice_length", h_bufobj->length);
41604 duk__debug_getinfo_prop_uint(thr, "elem_shift", (duk_uint_t) h_bufobj->shift);
41605 duk__debug_getinfo_prop_uint(thr, "elem_type", (duk_uint_t) h_bufobj->elem_type);
41606 duk__debug_getinfo_prop_bool(thr, "is_typedarray", (duk_uint_t) h_bufobj->is_typedarray);
41607 if (h_bufobj->buf != NULL) {
41608 duk__debug_getinfo_flags_key(thr, "buffer");
41609 duk_debug_write_heapptr(thr, (duk_heaphdr *) h_bufobj->buf);
41610 }
41611 }
41612#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
41613 break;
41614 }
41615 case DUK_HTYPE_BUFFER: {
41616 duk_hbuffer *h_buf;
41617
41618 h_buf = (duk_hbuffer *) h;
41619 duk__debug_getinfo_bitmask(thr,
41620 duk__debug_getinfo_hbuffer_keys,
41621 duk__debug_getinfo_hbuffer_masks,
41622 DUK_HEAPHDR_GET_FLAGS_RAW(h));
41623 duk__debug_getinfo_prop_uint(thr, "size", (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_buf));
41624 duk__debug_getinfo_flags_key(thr, "dataptr");
41625 duk_debug_write_pointer(thr, (void *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_buf));
41626 duk__debug_getinfo_flags_key(thr, "data");
41627 duk_debug_write_hbuffer(thr, h_buf); /* tolerates NULL h_buf */
41628 break;
41629 }
41630 default: {
41631 /* Since we already started writing the reply, just emit nothing. */
41632 DUK_D(DUK_DPRINT("inspect target pointer has invalid heaphdr type"));
41633 }
41634 }
41635
41636 duk_debug_write_eom(thr);
41637}
41638
41639DUK_LOCAL void duk__debug_handle_get_obj_prop_desc(duk_hthread *thr, duk_heap *heap) {
41640 duk_heaphdr *h;
41641 duk_hobject *h_obj;
41642 duk_hstring *h_key;
41643 duk_propdesc desc;
41644
41645 DUK_D(DUK_DPRINT("debug command GetObjPropDesc"));
41646 DUK_UNREF(heap);
41647
41648 h = duk_debug_read_any_ptr(thr);
41649 if (!h) {
41650 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid target");
41651 return;
41652 }
41653 h_key = duk_debug_read_hstring(thr);
41654 if (h == NULL || DUK_HEAPHDR_GET_TYPE(h) != DUK_HTYPE_OBJECT || h_key == NULL) {
41655 goto fail_args;
41656 }
41657 h_obj = (duk_hobject *) h;
41658
41659 if (duk_hobject_get_own_propdesc(thr, h_obj, h_key, &desc, 0 /*flags*/)) {
41660 duk_int_t virtual_idx;
41661 duk_bool_t rc;
41662
41663 /* To use the shared helper need the virtual index. */
41664 DUK_ASSERT(desc.e_idx >= 0 || desc.a_idx >= 0);
41665 virtual_idx = (desc.a_idx >= 0 ? desc.a_idx :
41666 (duk_int_t) DUK_HOBJECT_GET_ASIZE(h_obj) + desc.e_idx);
41667
41668 duk_debug_write_reply(thr);
41669 rc = duk__debug_getprop_index(thr, heap, h_obj, (duk_uint_t) virtual_idx);
41670 DUK_ASSERT(rc == 1);
41671 DUK_UNREF(rc);
41672 duk_debug_write_eom(thr);
41673 } else {
41674 duk_debug_write_error_eom(thr, DUK_DBG_ERR_NOTFOUND, "not found");
41675 }
41676 return;
41677
41678 fail_args:
41679 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid args");
41680}
41681
41682DUK_LOCAL void duk__debug_handle_get_obj_prop_desc_range(duk_hthread *thr, duk_heap *heap) {
41683 duk_heaphdr *h;
41684 duk_hobject *h_obj;
41685 duk_uint_t idx, idx_start, idx_end;
41686
41687 DUK_D(DUK_DPRINT("debug command GetObjPropDescRange"));
41688 DUK_UNREF(heap);
41689
41690 h = duk_debug_read_any_ptr(thr);
41691 idx_start = duk_debug_read_int(thr);
41692 idx_end = duk_debug_read_int(thr);
41693 if (h == NULL || DUK_HEAPHDR_GET_TYPE(h) != DUK_HTYPE_OBJECT) {
41694 goto fail_args;
41695 }
41696 h_obj = (duk_hobject *) h;
41697
41698 /* The index range space is conceptually the array part followed by the
41699 * entry part. Unlike normal enumeration all slots are exposed here as
41700 * is and return 'unused' if the slots are not in active use. In particular
41701 * the array part is included for the full a_size regardless of what the
41702 * array .length is.
41703 */
41704
41705 duk_debug_write_reply(thr);
41706 for (idx = idx_start; idx < idx_end; idx++) {
41707 if (!duk__debug_getprop_index(thr, heap, h_obj, idx)) {
41708 break;
41709 }
41710 }
41711 duk_debug_write_eom(thr);
41712 return;
41713
41714 fail_args:
41715 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNKNOWN, "invalid args");
41716}
41717
41718#endif /* DUK_USE_DEBUGGER_INSPECT */
41719
41720/*
41721 * Process incoming debug requests
41722 *
41723 * Individual request handlers can push temporaries on the value stack and
41724 * rely on duk__debug_process_message() to restore the value stack top
41725 * automatically.
41726 */
41727
41728/* Process one debug message. Automatically restore value stack top to its
41729 * entry value, so that individual message handlers don't need exact value
41730 * stack handling which is convenient.
41731 */
41732DUK_LOCAL void duk__debug_process_message(duk_hthread *thr) {
41733 duk_context *ctx = (duk_context *) thr;
41734 duk_heap *heap;
41735 duk_uint8_t x;
41736 duk_int32_t cmd;
41737 duk_idx_t entry_top;
41738
41739 DUK_ASSERT(thr != NULL);
41740 heap = thr->heap;
41741 DUK_ASSERT(heap != NULL);
41742 DUK_UNREF(ctx);
41743
41744 entry_top = duk_get_top(ctx);
41745
41746 x = duk_debug_read_byte(thr);
41747 switch (x) {
41748 case DUK_DBG_IB_REQUEST: {
41749 cmd = duk_debug_read_int(thr);
41750 switch (cmd) {
41751 case DUK_DBG_CMD_BASICINFO: {
41752 duk__debug_handle_basic_info(thr, heap);
41753 break;
41754 }
41755 case DUK_DBG_CMD_TRIGGERSTATUS: {
41756 duk__debug_handle_trigger_status(thr, heap);
41757 break;
41758 }
41759 case DUK_DBG_CMD_PAUSE: {
41760 duk__debug_handle_pause(thr, heap);
41761 break;
41762 }
41763 case DUK_DBG_CMD_RESUME: {
41764 duk__debug_handle_resume(thr, heap);
41765 break;
41766 }
41767 case DUK_DBG_CMD_STEPINTO:
41768 case DUK_DBG_CMD_STEPOVER:
41769 case DUK_DBG_CMD_STEPOUT: {
41770 duk__debug_handle_step(thr, heap, cmd);
41771 break;
41772 }
41773 case DUK_DBG_CMD_LISTBREAK: {
41774 duk__debug_handle_list_break(thr, heap);
41775 break;
41776 }
41777 case DUK_DBG_CMD_ADDBREAK: {
41778 duk__debug_handle_add_break(thr, heap);
41779 break;
41780 }
41781 case DUK_DBG_CMD_DELBREAK: {
41782 duk__debug_handle_del_break(thr, heap);
41783 break;
41784 }
41785 case DUK_DBG_CMD_GETVAR: {
41786 duk__debug_handle_get_var(thr, heap);
41787 break;
41788 }
41789 case DUK_DBG_CMD_PUTVAR: {
41790 duk__debug_handle_put_var(thr, heap);
41791 break;
41792 }
41793 case DUK_DBG_CMD_GETCALLSTACK: {
41794 duk__debug_handle_get_call_stack(thr, heap);
41795 break;
41796 }
41797 case DUK_DBG_CMD_GETLOCALS: {
41798 duk__debug_handle_get_locals(thr, heap);
41799 break;
41800 }
41801 case DUK_DBG_CMD_EVAL: {
41802 duk__debug_handle_eval(thr, heap);
41803 break;
41804 }
41805 case DUK_DBG_CMD_DETACH: {
41806 /* The actual detached_cb call is postponed to message loop so
41807 * we don't need any special precautions here (just skip to EOM
41808 * on the already closed connection).
41809 */
41810 duk__debug_handle_detach(thr, heap);
41811 break;
41812 }
41813#if defined(DUK_USE_DEBUGGER_DUMPHEAP)
41814 case DUK_DBG_CMD_DUMPHEAP: {
41815 duk__debug_handle_dump_heap(thr, heap);
41816 break;
41817 }
41818#endif /* DUK_USE_DEBUGGER_DUMPHEAP */
41819 case DUK_DBG_CMD_GETBYTECODE: {
41820 duk__debug_handle_get_bytecode(thr, heap);
41821 break;
41822 }
41823 case DUK_DBG_CMD_APPREQUEST: {
41824 duk__debug_handle_apprequest(thr, heap);
41825 break;
41826 }
41827#if defined(DUK_USE_DEBUGGER_INSPECT)
41828 case DUK_DBG_CMD_GETHEAPOBJINFO: {
41829 duk__debug_handle_get_heap_obj_info(thr, heap);
41830 break;
41831 }
41832 case DUK_DBG_CMD_GETOBJPROPDESC: {
41833 duk__debug_handle_get_obj_prop_desc(thr, heap);
41834 break;
41835 }
41836 case DUK_DBG_CMD_GETOBJPROPDESCRANGE: {
41837 duk__debug_handle_get_obj_prop_desc_range(thr, heap);
41838 break;
41839 }
41840#endif /* DUK_USE_DEBUGGER_INSPECT */
41841 default: {
41842 DUK_D(DUK_DPRINT("debug command unsupported: %d", (int) cmd));
41843 duk_debug_write_error_eom(thr, DUK_DBG_ERR_UNSUPPORTED, "unsupported command");
41844 }
41845 } /* switch cmd */
41846 break;
41847 }
41848 case DUK_DBG_IB_REPLY: {
41849 DUK_D(DUK_DPRINT("debug reply, skipping"));
41850 break;
41851 }
41852 case DUK_DBG_IB_ERROR: {
41853 DUK_D(DUK_DPRINT("debug error, skipping"));
41854 break;
41855 }
41856 case DUK_DBG_IB_NOTIFY: {
41857 DUK_D(DUK_DPRINT("debug notify, skipping"));
41858 break;
41859 }
41860 default: {
41861 DUK_D(DUK_DPRINT("invalid initial byte, drop connection: %d", (int) x));
41862 goto fail;
41863 }
41864 } /* switch initial byte */
41865
41866 DUK_ASSERT(duk_get_top(ctx) >= entry_top);
41867 duk_set_top(ctx, entry_top);
41868 duk__debug_skip_to_eom(thr);
41869 return;
41870
41871 fail:
41872 DUK_ASSERT(duk_get_top(ctx) >= entry_top);
41873 duk_set_top(ctx, entry_top);
41874 DUK__SET_CONN_BROKEN(thr, 1);
41875 return;
41876}
41877
41878DUK_LOCAL void duk__check_resend_status(duk_hthread *thr) {
41879 if (thr->heap->dbg_read_cb != NULL && thr->heap->dbg_state_dirty) {
41880 duk_debug_send_status(thr);
41881 thr->heap->dbg_state_dirty = 0;
41882 }
41883}
41884
41885DUK_INTERNAL duk_bool_t duk_debug_process_messages(duk_hthread *thr, duk_bool_t no_block) {
41886 duk_context *ctx = (duk_context *) thr;
41887#if defined(DUK_USE_ASSERTIONS)
41888 duk_idx_t entry_top;
41889#endif
41890 duk_bool_t retval = 0;
41891
41892 DUK_ASSERT(thr != NULL);
41893 DUK_UNREF(ctx);
41894 DUK_ASSERT(thr->heap != NULL);
41895#if defined(DUK_USE_ASSERTIONS)
41896 entry_top = duk_get_top(ctx);
41897#endif
41898
41899 DUK_D(DUK_DPRINT("process debug messages: read_cb=%s, no_block=%ld, detaching=%ld, processing=%ld",
41900 thr->heap->dbg_read_cb ? "not NULL" : "NULL", (long) no_block,
41901 (long) thr->heap->dbg_detaching, (long) thr->heap->dbg_processing));
41902 DUK_DD(DUK_DDPRINT("top at entry: %ld", (long) duk_get_top(ctx)));
41903
41904 /* thr->heap->dbg_detaching may be != 0 if a debugger write outside
41905 * the message loop caused a transport error and detach1() to run.
41906 */
41907 DUK_ASSERT(thr->heap->dbg_detaching == 0 || thr->heap->dbg_detaching == 1);
41908 DUK_ASSERT(thr->heap->dbg_processing == 0);
41909 thr->heap->dbg_processing = 1;
41910
41911 /* Ensure dirty state causes a Status even if never process any
41912 * messages. This is expected by the bytecode executor when in
41913 * the running state.
41914 */
41915 duk__check_resend_status(thr);
41916
41917 for (;;) {
41918 /* Process messages until we're no longer paused or we peek
41919 * and see there's nothing to read right now.
41920 */
41921 DUK_DD(DUK_DDPRINT("top at loop top: %ld", (long) duk_get_top(ctx)));
41922 DUK_ASSERT(thr->heap->dbg_processing == 1);
41923
41924 while (thr->heap->dbg_read_cb == NULL && thr->heap->dbg_detaching) {
41925 /* Detach is pending; can be triggered from outside the
41926 * debugger loop (e.g. Status notify write error) or by
41927 * previous message handling. Call detached callback
41928 * here, in a controlled state, to ensure a possible
41929 * reattach inside the detached_cb is handled correctly.
41930 *
41931 * Recheck for detach in a while loop: an immediate
41932 * reattach involves a call to duk_debugger_attach()
41933 * which writes a debugger handshake line immediately
41934 * inside the API call. If the transport write fails
41935 * for that handshake, we can immediately end up in a
41936 * "transport broken, detaching" case several times here.
41937 * Loop back until we're either cleanly attached or
41938 * fully detached.
41939 *
41940 * NOTE: Reset dbg_processing = 1 forcibly, in case we
41941 * re-attached; duk_debugger_attach() sets dbg_processing
41942 * to 0 at the moment.
41943 */
41944
41945 DUK_D(DUK_DPRINT("detach pending (dbg_read_cb == NULL, dbg_detaching != 0), call detach2"));
41946
41947 duk__debug_do_detach2(thr->heap);
41948 thr->heap->dbg_processing = 1; /* may be set to 0 by duk_debugger_attach() inside callback */
41949
41950 DUK_D(DUK_DPRINT("after detach2 (and possible reattach): dbg_read_cb=%s, dbg_detaching=%ld",
41951 thr->heap->dbg_read_cb ? "not NULL" : "NULL", (long) thr->heap->dbg_detaching));
41952 }
41953 DUK_ASSERT(thr->heap->dbg_detaching == 0); /* true even with reattach */
41954 DUK_ASSERT(thr->heap->dbg_processing == 1); /* even after a detach and possible reattach */
41955
41956 if (thr->heap->dbg_read_cb == NULL) {
41957 DUK_D(DUK_DPRINT("debug connection broken (and not detaching), stop processing messages"));
41958 break;
41959 }
41960
41961 if (!DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) || no_block) {
41962 if (!duk_debug_read_peek(thr)) {
41963 /* Note: peek cannot currently trigger a detach
41964 * so the dbg_detaching == 0 assert outside the
41965 * loop is correct.
41966 */
41967 DUK_D(DUK_DPRINT("processing debug message, peek indicated no data, stop processing messages"));
41968 break;
41969 }
41970 DUK_D(DUK_DPRINT("processing debug message, peek indicated there is data, handle it"));
41971 } else {
41972 DUK_D(DUK_DPRINT("paused, process debug message, blocking if necessary"));
41973 }
41974
41975 duk__check_resend_status(thr);
41976 duk__debug_process_message(thr);
41977 duk__check_resend_status(thr);
41978
41979 retval = 1; /* processed one or more messages */
41980 }
41981
41982 DUK_ASSERT(thr->heap->dbg_detaching == 0);
41983 DUK_ASSERT(thr->heap->dbg_processing == 1);
41984 thr->heap->dbg_processing = 0;
41985
41986 /* As an initial implementation, read flush after exiting the message
41987 * loop. If transport is broken, this is a no-op (with debug logs).
41988 */
41989 duk_debug_read_flush(thr); /* this cannot initiate a detach */
41990 DUK_ASSERT(thr->heap->dbg_detaching == 0);
41991
41992 DUK_DD(DUK_DDPRINT("top at exit: %ld", (long) duk_get_top(ctx)));
41993
41994#if defined(DUK_USE_ASSERTIONS)
41995 /* Easy to get wrong, so assert for it. */
41996 DUK_ASSERT(entry_top == duk_get_top(ctx));
41997#endif
41998
41999 return retval;
42000}
42001
42002/*
42003 * Halt execution helper
42004 */
42005
42006/* Halt execution and enter a debugger message loop until execution is resumed
42007 * by the client. PC for the current activation may be temporarily decremented
42008 * so that the "current" instruction will be shown by the client. This helper
42009 * is callable from anywhere, also outside bytecode executor.
42010 */
42011
42012DUK_INTERNAL void duk_debug_halt_execution(duk_hthread *thr, duk_bool_t use_prev_pc) {
42013 duk_activation *act;
42014 duk_hcompfunc *fun;
42015 duk_instr_t *old_pc = NULL;
42016
42017 DUK_ASSERT(thr != NULL);
42018 DUK_ASSERT(thr->heap != NULL);
42019 DUK_ASSERT(DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap));
42020 DUK_ASSERT(thr->heap->dbg_processing == 0);
42021
42022 DUK_HEAP_SET_PAUSED(thr->heap);
42023
42024 act = duk_hthread_get_current_activation(thr);
42025
42026 /* NOTE: act may be NULL if an error is thrown outside of any activation,
42027 * which may happen in the case of, e.g. syntax errors.
42028 */
42029
42030 /* Decrement PC if that was requested, this requires a PC sync. */
42031 if (act != NULL) {
42032 duk_hthread_sync_currpc(thr);
42033 old_pc = act->curr_pc;
42034 fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
42035
42036 /* Short circuit if is safe: if act->curr_pc != NULL, 'fun' is
42037 * guaranteed to be a non-NULL Ecmascript function.
42038 */
42039 DUK_ASSERT(act->curr_pc == NULL ||
42040 (fun != NULL && DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) fun)));
42041 if (use_prev_pc &&
42042 act->curr_pc != NULL &&
42043 act->curr_pc > DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, fun)) {
42044 act->curr_pc--;
42045 }
42046 }
42047
42048 /* Process debug messages until we are no longer paused. */
42049
42050 /* NOTE: This is a bit fragile. It's important to ensure that
42051 * duk_debug_process_messages() never throws an error or
42052 * act->curr_pc will never be reset.
42053 */
42054
42055 thr->heap->dbg_state_dirty = 1;
42056 while (DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap)) {
42057 DUK_ASSERT(DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap));
42058 DUK_ASSERT(thr->heap->dbg_processing);
42059 duk_debug_process_messages(thr, 0 /*no_block*/);
42060 }
42061
42062 /* XXX: Decrementing and restoring act->curr_pc works now, but if the
42063 * debugger message loop gains the ability to adjust the current PC
42064 * (e.g. a forced jump) restoring the PC here will break. Another
42065 * approach would be to use a state flag for the "decrement 1 from
42066 * topmost activation's PC" and take it into account whenever dealing
42067 * with PC values.
42068 */
42069 if (act != NULL) {
42070 act->curr_pc = old_pc; /* restore PC */
42071 }
42072}
42073
42074/*
42075 * Breakpoint management
42076 */
42077
42078DUK_INTERNAL duk_small_int_t duk_debug_add_breakpoint(duk_hthread *thr, duk_hstring *filename, duk_uint32_t line) {
42079 duk_heap *heap;
42080 duk_breakpoint *b;
42081
42082 /* Caller must trigger recomputation of active breakpoint list. To
42083 * ensure stale values are not used if that doesn't happen, clear the
42084 * active breakpoint list here.
42085 */
42086
42087 DUK_ASSERT(thr != NULL);
42088 DUK_ASSERT(filename != NULL);
42089 heap = thr->heap;
42090 DUK_ASSERT(heap != NULL);
42091
42092 if (heap->dbg_breakpoint_count >= DUK_HEAP_MAX_BREAKPOINTS) {
42093 DUK_D(DUK_DPRINT("failed to add breakpoint for %O:%ld, all breakpoint slots used",
42094 (duk_heaphdr *) filename, (long) line));
42095 return -1;
42096 }
42097 heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL;
42098 b = heap->dbg_breakpoints + (heap->dbg_breakpoint_count++);
42099 b->filename = filename;
42100 b->line = line;
42101 DUK_HSTRING_INCREF(thr, filename);
42102
42103 return heap->dbg_breakpoint_count - 1; /* index */
42104}
42105
42106DUK_INTERNAL duk_bool_t duk_debug_remove_breakpoint(duk_hthread *thr, duk_small_uint_t breakpoint_index) {
42107 duk_heap *heap;
42108 duk_hstring *h;
42109 duk_breakpoint *b;
42110 duk_size_t move_size;
42111
42112 /* Caller must trigger recomputation of active breakpoint list. To
42113 * ensure stale values are not used if that doesn't happen, clear the
42114 * active breakpoint list here.
42115 */
42116
42117 DUK_ASSERT(thr != NULL);
42118 heap = thr->heap;
42119 DUK_ASSERT(heap != NULL);
42120 DUK_ASSERT(DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap));
42121 DUK_ASSERT_DISABLE(breakpoint_index >= 0); /* unsigned */
42122
42123 if (breakpoint_index >= heap->dbg_breakpoint_count) {
42124 DUK_D(DUK_DPRINT("invalid breakpoint index: %ld", (long) breakpoint_index));
42125 return 0;
42126 }
42127 b = heap->dbg_breakpoints + breakpoint_index;
42128
42129 h = b->filename;
42130 DUK_ASSERT(h != NULL);
42131
42132 move_size = sizeof(duk_breakpoint) * (heap->dbg_breakpoint_count - breakpoint_index - 1);
42133 if (move_size > 0) {
42134 DUK_MEMMOVE((void *) b,
42135 (const void *) (b + 1),
42136 (size_t) move_size);
42137 }
42138 heap->dbg_breakpoint_count--;
42139 heap->dbg_breakpoints_active[0] = (duk_breakpoint *) NULL;
42140
42141 DUK_HSTRING_DECREF(thr, h); /* side effects */
42142 DUK_UNREF(h); /* w/o refcounting */
42143
42144 /* Breakpoint entries above the used area are left as garbage. */
42145
42146 return 1;
42147}
42148
42149#else /* DUK_USE_DEBUGGER_SUPPORT */
42150
42151/* No debugger support. */
42152
42153#endif /* DUK_USE_DEBUGGER_SUPPORT */
42154
42155/* automatic undefs */
42156#undef DUK__SET_CONN_BROKEN
42157/*
42158 * Augmenting errors at their creation site and their throw site.
42159 *
42160 * When errors are created, traceback data is added by built-in code
42161 * and a user error handler (if defined) can process or replace the
42162 * error. Similarly, when errors are thrown, a user error handler
42163 * (if defined) can process or replace the error.
42164 *
42165 * Augmentation and other processing at error creation time is nice
42166 * because an error is only created once, but it may be thrown and
42167 * rethrown multiple times. User error handler registered for processing
42168 * an error at its throw site must be careful to handle rethrowing in
42169 * a useful manner.
42170 *
42171 * Error augmentation may throw an internal error (e.g. alloc error).
42172 *
42173 * Ecmascript allows throwing any values, so all values cannot be
42174 * augmented. Currently, the built-in augmentation at error creation
42175 * only augments error values which are Error instances (= have the
42176 * built-in Error.prototype in their prototype chain) and are also
42177 * extensible. User error handlers have no limitations in this respect.
42178 */
42179
42180/* #include duk_internal.h -> already included */
42181
42182/*
42183 * Helper for calling a user error handler.
42184 *
42185 * 'thr' must be the currently active thread; the error handler is called
42186 * in its context. The valstack of 'thr' must have the error value on
42187 * top, and will be replaced by another error value based on the return
42188 * value of the error handler.
42189 *
42190 * The helper calls duk_handle_call() recursively in protected mode.
42191 * Before that call happens, no longjmps should happen; as a consequence,
42192 * we must assume that the valstack contains enough temporary space for
42193 * arguments and such.
42194 *
42195 * While the error handler runs, any errors thrown will not trigger a
42196 * recursive error handler call (this is implemented using a heap level
42197 * flag which will "follow" through any coroutines resumed inside the
42198 * error handler). If the error handler is not callable or throws an
42199 * error, the resulting error replaces the original error (for Duktape
42200 * internal errors, duk_error_throw.c further substitutes this error with
42201 * a DoubleError which is not ideal). This would be easy to change and
42202 * even signal to the caller.
42203 *
42204 * The user error handler is stored in 'Duktape.errCreate' or
42205 * 'Duktape.errThrow' depending on whether we're augmenting the error at
42206 * creation or throw time. There are several alternatives to this approach,
42207 * see doc/error-objects.rst for discussion.
42208 *
42209 * Note: since further longjmp()s may occur while calling the error handler
42210 * (for many reasons, e.g. a labeled 'break' inside the handler), the
42211 * caller can make no assumptions on the thr->heap->lj state after the
42212 * call (this affects especially duk_error_throw.c). This is not an issue
42213 * as long as the caller writes to the lj state only after the error handler
42214 * finishes.
42215 */
42216
42217#if defined(DUK_USE_ERRTHROW) || defined(DUK_USE_ERRCREATE)
42218DUK_LOCAL void duk__err_augment_user(duk_hthread *thr, duk_small_uint_t stridx_cb) {
42219 duk_context *ctx = (duk_context *) thr;
42220 duk_tval *tv_hnd;
42221 duk_small_uint_t call_flags;
42222 duk_int_t rc;
42223
42224 DUK_ASSERT(thr != NULL);
42225 DUK_ASSERT(thr->heap != NULL);
42226 DUK_ASSERT_STRIDX_VALID(stridx_cb);
42227
42228 if (DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap)) {
42229 DUK_DD(DUK_DDPRINT("recursive call to error handler, ignore"));
42230 return;
42231 }
42232
42233 /*
42234 * Check whether or not we have an error handler.
42235 *
42236 * We must be careful of not triggering an error when looking up the
42237 * property. For instance, if the property is a getter, we don't want
42238 * to call it, only plain values are allowed. The value, if it exists,
42239 * is not checked. If the value is not a function, a TypeError happens
42240 * when it is called and that error replaces the original one.
42241 */
42242
42243 DUK_ASSERT_VALSTACK_SPACE(thr, 4); /* 3 entries actually needed below */
42244
42245 /* [ ... errval ] */
42246
42247 if (thr->builtins[DUK_BIDX_DUKTAPE] == NULL) {
42248 /* When creating built-ins, some of the built-ins may not be set
42249 * and we want to tolerate that when throwing errors.
42250 */
42251 DUK_DD(DUK_DDPRINT("error occurred when DUK_BIDX_DUKTAPE is NULL, ignoring"));
42252 return;
42253 }
42254 tv_hnd = duk_hobject_find_existing_entry_tval_ptr(thr->heap,
42255 thr->builtins[DUK_BIDX_DUKTAPE],
42256 DUK_HTHREAD_GET_STRING(thr, stridx_cb));
42257 if (tv_hnd == NULL) {
42258 DUK_DD(DUK_DDPRINT("error handler does not exist or is not a plain value: %!T",
42259 (duk_tval *) tv_hnd));
42260 return;
42261 }
42262 DUK_DDD(DUK_DDDPRINT("error handler dump (callability not checked): %!T",
42263 (duk_tval *) tv_hnd));
42264 duk_push_tval(ctx, tv_hnd);
42265
42266 /* [ ... errval errhandler ] */
42267
42268 duk_insert(ctx, -2); /* -> [ ... errhandler errval ] */
42269 duk_push_undefined(ctx);
42270 duk_insert(ctx, -2); /* -> [ ... errhandler undefined(= this) errval ] */
42271
42272 /* [ ... errhandler undefined errval ] */
42273
42274 /*
42275 * DUK_CALL_FLAG_IGNORE_RECLIMIT causes duk_handle_call() to ignore C
42276 * recursion depth limit (and won't increase it either). This is
42277 * dangerous, but useful because it allows the error handler to run
42278 * even if the original error is caused by C recursion depth limit.
42279 *
42280 * The heap level DUK_HEAP_FLAG_ERRHANDLER_RUNNING is set for the
42281 * duration of the error handler and cleared afterwards. This flag
42282 * prevents the error handler from running recursively. The flag is
42283 * heap level so that the flag properly controls even coroutines
42284 * launched by an error handler. Since the flag is heap level, it is
42285 * critical to restore it correctly.
42286 *
42287 * We ignore errors now: a success return and an error value both
42288 * replace the original error value. (This would be easy to change.)
42289 */
42290
42291 DUK_ASSERT(!DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap)); /* since no recursive error handler calls */
42292 DUK_HEAP_SET_ERRHANDLER_RUNNING(thr->heap);
42293
42294 call_flags = DUK_CALL_FLAG_IGNORE_RECLIMIT; /* ignore reclimit, not constructor */
42295
42296 rc = duk_handle_call_protected(thr,
42297 1, /* num args */
42298 call_flags); /* call_flags */
42299 DUK_UNREF(rc); /* no need to check now: both success and error are OK */
42300
42301 DUK_ASSERT(DUK_HEAP_HAS_ERRHANDLER_RUNNING(thr->heap));
42302 DUK_HEAP_CLEAR_ERRHANDLER_RUNNING(thr->heap);
42303
42304 /* [ ... errval ] */
42305}
42306#endif /* DUK_USE_ERRTHROW || DUK_USE_ERRCREATE */
42307
42308/*
42309 * Add ._Tracedata to an error on the stack top.
42310 */
42311
42312#if defined(DUK_USE_TRACEBACKS)
42313DUK_LOCAL void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_bool_t noblame_fileline) {
42314 duk_context *ctx = (duk_context *) thr;
42315 duk_small_uint_t depth;
42316 duk_int_t i, i_min;
42317 duk_int_t arr_size;
42318 duk_harray *a;
42319 duk_tval *tv;
42320 duk_hstring *s;
42321 duk_uint32_t u32;
42322 duk_double_t d;
42323
42324 DUK_ASSERT(thr != NULL);
42325 DUK_ASSERT(thr_callstack != NULL);
42326 DUK_ASSERT(ctx != NULL);
42327
42328 /* [ ... error ] */
42329
42330 /*
42331 * The traceback format is pretty arcane in an attempt to keep it compact
42332 * and cheap to create. It may change arbitrarily from version to version.
42333 * It should be decoded/accessed through version specific accessors only.
42334 *
42335 * See doc/error-objects.rst.
42336 */
42337
42338 DUK_DDD(DUK_DDDPRINT("adding traceback to object: %!T",
42339 (duk_tval *) duk_get_tval(ctx, -1)));
42340
42341 /* Preallocate array to correct size, so that we can just write out
42342 * the _Tracedata values into the array part.
42343 */
42344 depth = DUK_USE_TRACEBACK_DEPTH;
42345 arr_size = (duk_int_t) (thr_callstack->callstack_top <= depth ? thr_callstack->callstack_top : depth) * 2;
42346 if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) {
42347 arr_size += 2;
42348 }
42349 if (c_filename) {
42350 /* We need the C filename to be interned before getting the
42351 * array part pointer to avoid any GC interference while the
42352 * array part is populated.
42353 */
42354 duk_push_string(ctx, c_filename);
42355 arr_size += 2;
42356 }
42357
42358 DUK_D(DUK_DPRINT("preallocated _Tracedata to %ld items", (long) arr_size));
42359 a = duk_push_harray_with_size(ctx, (duk_uint32_t) arr_size); /* XXX: call which returns array part pointer directly */
42360 DUK_ASSERT(a != NULL);
42361 tv = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a);
42362 DUK_ASSERT(tv != NULL || arr_size == 0);
42363
42364 /* Compiler SyntaxErrors (and other errors) come first, and are
42365 * blamed by default (not flagged "noblame").
42366 */
42367 if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) {
42368 s = thr->compile_ctx->h_filename;
42369 DUK_TVAL_SET_STRING(tv, s);
42370 DUK_HSTRING_INCREF(thr, s);
42371 tv++;
42372
42373 u32 = (duk_uint32_t) thr->compile_ctx->curr_token.start_line; /* (flags<<32) + (line), flags = 0 */
42374 DUK_TVAL_SET_U32(tv, u32);
42375 tv++;
42376 }
42377
42378 /* Filename/line from C macros (__FILE__, __LINE__) are added as an
42379 * entry with a special format: (string, number). The number contains
42380 * the line and flags.
42381 */
42382
42383 /* [ ... error c_filename? arr ] */
42384
42385 if (c_filename) {
42386 DUK_ASSERT(DUK_TVAL_IS_STRING(thr->valstack_top - 2));
42387 s = DUK_TVAL_GET_STRING(thr->valstack_top - 2); /* interned c_filename */
42388 DUK_ASSERT(s != NULL);
42389 DUK_TVAL_SET_STRING(tv, s);
42390 DUK_HSTRING_INCREF(thr, s);
42391 tv++;
42392
42393 d = (noblame_fileline ? ((duk_double_t) DUK_TB_FLAG_NOBLAME_FILELINE) * DUK_DOUBLE_2TO32 : 0.0) +
42394 (duk_double_t) c_line;
42395 DUK_TVAL_SET_DOUBLE(tv, d);
42396 tv++;
42397 }
42398
42399 /* traceback depth doesn't take into account the filename/line
42400 * special handling above (intentional)
42401 */
42402 depth = DUK_USE_TRACEBACK_DEPTH;
42403 i_min = (thr_callstack->callstack_top > (duk_size_t) depth ? (duk_int_t) (thr_callstack->callstack_top - depth) : 0);
42404 DUK_ASSERT(i_min >= 0);
42405
42406 /* [ ... error c_filename? arr ] */
42407
42408 DUK_ASSERT(thr_callstack->callstack_top <= DUK_INT_MAX); /* callstack limits */
42409 for (i = (duk_int_t) (thr_callstack->callstack_top - 1); i >= i_min; i--) {
42410 duk_uint32_t pc;
42411 duk_tval *tv_src;
42412
42413 /*
42414 * Note: each API operation potentially resizes the callstack,
42415 * so be careful to re-lookup after every operation. Currently
42416 * these is no issue because we don't store a temporary 'act'
42417 * pointer at all. (This would be a non-issue if we operated
42418 * directly on the array part.)
42419 */
42420
42421 /* [... arr] */
42422
42423 DUK_ASSERT_DISABLE(thr_callstack->callstack[i].pc >= 0); /* unsigned */
42424
42425 /* Add function object. */
42426 tv_src = &(thr_callstack->callstack + i)->tv_func; /* object (function) or lightfunc */
42427 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_src) || DUK_TVAL_IS_LIGHTFUNC(tv_src));
42428 DUK_TVAL_SET_TVAL(tv, tv_src);
42429 DUK_TVAL_INCREF(thr, tv);
42430 tv++;
42431
42432 /* Add a number containing: pc, activation flags.
42433 *
42434 * PC points to next instruction, find offending PC. Note that
42435 * PC == 0 for native code.
42436 */
42437 pc = duk_hthread_get_act_prev_pc(thr_callstack, thr_callstack->callstack + i);
42438 DUK_ASSERT_DISABLE(pc >= 0); /* unsigned */
42439 DUK_ASSERT((duk_double_t) pc < DUK_DOUBLE_2TO32); /* assume PC is at most 32 bits and non-negative */
42440 d = ((duk_double_t) thr_callstack->callstack[i].flags) * DUK_DOUBLE_2TO32 + (duk_double_t) pc;
42441 DUK_TVAL_SET_DOUBLE(tv, d);
42442 tv++;
42443 }
42444
42445 DUK_ASSERT((duk_uint32_t) (tv - DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a)) == a->length);
42446 DUK_ASSERT(a->length == (duk_uint32_t) arr_size);
42447
42448 /* [ ... error c_filename? arr ] */
42449
42450 if (c_filename) {
42451 duk_remove_m2(ctx);
42452 }
42453
42454 /* [ ... error arr ] */
42455
42456 duk_xdef_prop_stridx_short_wec(ctx, -2, DUK_STRIDX_INT_TRACEDATA); /* -> [ ... error ] */
42457}
42458#endif /* DUK_USE_TRACEBACKS */
42459
42460/*
42461 * Add .fileName and .lineNumber to an error on the stack top.
42462 */
42463
42464#if defined(DUK_USE_AUGMENT_ERROR_CREATE) && !defined(DUK_USE_TRACEBACKS)
42465DUK_LOCAL void duk__add_fileline(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_bool_t noblame_fileline) {
42466 duk_context *ctx;
42467#if defined(DUK_USE_ASSERTIONS)
42468 duk_int_t entry_top;
42469#endif
42470
42471 ctx = (duk_context *) thr;
42472#if defined(DUK_USE_ASSERTIONS)
42473 entry_top = duk_get_top(ctx);
42474#endif
42475
42476 /*
42477 * If tracebacks are disabled, 'fileName' and 'lineNumber' are added
42478 * as plain own properties. Since Error.prototype has accessors of
42479 * the same name, we need to define own properties directly (cannot
42480 * just use e.g. duk_put_prop_stridx). Existing properties are not
42481 * overwritten in case they already exist.
42482 */
42483
42484 if (thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL) {
42485 /* Compiler SyntaxError (or other error) gets the primary blame.
42486 * Currently no flag to prevent blaming.
42487 */
42488 duk_push_uint(ctx, (duk_uint_t) thr->compile_ctx->curr_token.start_line);
42489 duk_push_hstring(ctx, thr->compile_ctx->h_filename);
42490 } else if (c_filename && !noblame_fileline) {
42491 /* C call site gets blamed next, unless flagged not to do so.
42492 * XXX: file/line is disabled in minimal builds, so disable this
42493 * too when appropriate.
42494 */
42495 duk_push_int(ctx, c_line);
42496 duk_push_string(ctx, c_filename);
42497 } else {
42498 /* Finally, blame the innermost callstack entry which has a
42499 * .fileName property.
42500 */
42501 duk_small_uint_t depth;
42502 duk_int_t i, i_min;
42503 duk_uint32_t ecma_line;
42504
42505 depth = DUK_USE_TRACEBACK_DEPTH;
42506 i_min = (thr_callstack->callstack_top > (duk_size_t) depth ? (duk_int_t) (thr_callstack->callstack_top - depth) : 0);
42507 DUK_ASSERT(i_min >= 0);
42508
42509 DUK_ASSERT(thr_callstack->callstack_top <= DUK_INT_MAX); /* callstack limits */
42510 for (i = (duk_int_t) (thr_callstack->callstack_top - 1); i >= i_min; i--) {
42511 duk_activation *act;
42512 duk_hobject *func;
42513 duk_uint32_t pc;
42514
42515 DUK_UNREF(pc);
42516 act = thr_callstack->callstack + i;
42517 DUK_ASSERT(act >= thr_callstack->callstack && act < thr_callstack->callstack + thr_callstack->callstack_size);
42518
42519 func = DUK_ACT_GET_FUNC(act);
42520 if (func == NULL) {
42521 /* Lightfunc, not blamed now. */
42522 continue;
42523 }
42524
42525 /* PC points to next instruction, find offending PC,
42526 * PC == 0 for native code.
42527 */
42528 pc = duk_hthread_get_act_prev_pc(thr, act); /* thr argument only used for thr->heap, so specific thread doesn't matter */
42529 DUK_ASSERT_DISABLE(pc >= 0); /* unsigned */
42530 DUK_ASSERT((duk_double_t) pc < DUK_DOUBLE_2TO32); /* assume PC is at most 32 bits and non-negative */
42531 act = NULL; /* invalidated by pushes, so get out of the way */
42532
42533 duk_push_hobject(ctx, func);
42534
42535 /* [ ... error func ] */
42536
42537 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_FILE_NAME);
42538 if (!duk_is_string_notsymbol(ctx, -1)) {
42539 duk_pop_2(ctx);
42540 continue;
42541 }
42542
42543 /* [ ... error func fileName ] */
42544
42545 ecma_line = 0;
42546#if defined(DUK_USE_PC2LINE)
42547 if (DUK_HOBJECT_IS_COMPFUNC(func)) {
42548 ecma_line = duk_hobject_pc2line_query(ctx, -2, (duk_uint_fast32_t) pc);
42549 } else {
42550 /* Native function, no relevant lineNumber. */
42551 }
42552#endif /* DUK_USE_PC2LINE */
42553 duk_push_u32(ctx, ecma_line);
42554
42555 /* [ ... error func fileName lineNumber ] */
42556
42557 duk_replace(ctx, -3);
42558
42559 /* [ ... error lineNumber fileName ] */
42560 goto define_props;
42561 }
42562
42563 /* No activation matches, use undefined for both .fileName and
42564 * .lineNumber (matches what we do with a _Tracedata based
42565 * no-match lookup.
42566 */
42567 duk_push_undefined(ctx);
42568 duk_push_undefined(ctx);
42569 }
42570
42571 define_props:
42572 /* [ ... error lineNumber fileName ] */
42573#if defined(DUK_USE_ASSERTIONS)
42574 DUK_ASSERT(duk_get_top(ctx) == entry_top + 2);
42575#endif
42576 duk_xdef_prop_stridx_short(ctx, -3, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_C | DUK_PROPDESC_FLAG_NO_OVERWRITE);
42577 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_LINE_NUMBER, DUK_PROPDESC_FLAGS_C | DUK_PROPDESC_FLAG_NO_OVERWRITE);
42578}
42579#endif /* DUK_USE_AUGMENT_ERROR_CREATE && !DUK_USE_TRACEBACKS */
42580
42581/*
42582 * Add line number to a compiler error.
42583 */
42584
42585#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
42586DUK_LOCAL void duk__add_compiler_error_line(duk_hthread *thr) {
42587 duk_context *ctx;
42588
42589 /* Append a "(line NNN)" to the "message" property of any error
42590 * thrown during compilation. Usually compilation errors are
42591 * SyntaxErrors but they can also be out-of-memory errors and
42592 * the like.
42593 */
42594
42595 /* [ ... error ] */
42596
42597 ctx = (duk_context *) thr;
42598 DUK_ASSERT(duk_is_object(ctx, -1));
42599
42600 if (!(thr->compile_ctx != NULL && thr->compile_ctx->h_filename != NULL)) {
42601 return;
42602 }
42603
42604 DUK_DDD(DUK_DDDPRINT("compile error, before adding line info: %!T",
42605 (duk_tval *) duk_get_tval(ctx, -1)));
42606
42607 if (duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_MESSAGE)) {
42608 duk_push_sprintf(ctx, " (line %ld)", (long) thr->compile_ctx->curr_token.start_line);
42609 duk_concat(ctx, 2);
42610 duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_MESSAGE);
42611 } else {
42612 duk_pop(ctx);
42613 }
42614
42615 DUK_DDD(DUK_DDDPRINT("compile error, after adding line info: %!T",
42616 (duk_tval *) duk_get_tval(ctx, -1)));
42617}
42618#endif /* DUK_USE_AUGMENT_ERROR_CREATE */
42619
42620/*
42621 * Augment an error being created using Duktape specific properties
42622 * like _Tracedata or .fileName/.lineNumber.
42623 */
42624
42625#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
42626DUK_LOCAL void duk__err_augment_builtin_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_small_int_t noblame_fileline, duk_hobject *obj) {
42627 duk_context *ctx = (duk_context *) thr;
42628#if defined(DUK_USE_ASSERTIONS)
42629 duk_int_t entry_top;
42630#endif
42631
42632#if defined(DUK_USE_ASSERTIONS)
42633 entry_top = duk_get_top(ctx);
42634#endif
42635 DUK_ASSERT(obj != NULL);
42636
42637 DUK_UNREF(obj); /* unreferenced w/o tracebacks */
42638 DUK_UNREF(ctx); /* unreferenced w/o asserts */
42639
42640 duk__add_compiler_error_line(thr);
42641
42642#if defined(DUK_USE_TRACEBACKS)
42643 /* If tracebacks are enabled, the '_Tracedata' property is the only
42644 * thing we need: 'fileName' and 'lineNumber' are virtual properties
42645 * which use '_Tracedata'.
42646 */
42647 if (duk_hobject_hasprop_raw(thr, obj, DUK_HTHREAD_STRING_INT_TRACEDATA(thr))) {
42648 DUK_DDD(DUK_DDDPRINT("error value already has a '_Tracedata' property, not modifying it"));
42649 } else {
42650 duk__add_traceback(thr, thr_callstack, c_filename, c_line, noblame_fileline);
42651 }
42652#else
42653 /* Without tracebacks the concrete .fileName and .lineNumber need
42654 * to be added directly.
42655 */
42656 duk__add_fileline(thr, thr_callstack, c_filename, c_line, noblame_fileline);
42657#endif
42658
42659#if defined(DUK_USE_ASSERTIONS)
42660 DUK_ASSERT(duk_get_top(ctx) == entry_top);
42661#endif
42662}
42663#endif /* DUK_USE_AUGMENT_ERROR_CREATE */
42664
42665/*
42666 * Augment an error at creation time with _Tracedata/fileName/lineNumber
42667 * and allow a user error handler (if defined) to process/replace the error.
42668 * The error to be augmented is at the stack top.
42669 *
42670 * thr: thread containing the error value
42671 * thr_callstack: thread which should be used for generating callstack etc.
42672 * c_filename: C __FILE__ related to the error
42673 * c_line: C __LINE__ related to the error
42674 * noblame_fileline: if true, don't fileName/line as error source, otherwise use traceback
42675 * (needed because user code filename/line are reported but internal ones
42676 * are not)
42677 *
42678 * XXX: rename noblame_fileline to flags field; combine it to some existing
42679 * field (there are only a few call sites so this may not be worth it).
42680 */
42681
42682#if defined(DUK_USE_AUGMENT_ERROR_CREATE)
42683DUK_INTERNAL void duk_err_augment_error_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_bool_t noblame_fileline) {
42684 duk_context *ctx = (duk_context *) thr;
42685 duk_hobject *obj;
42686
42687 DUK_ASSERT(thr != NULL);
42688 DUK_ASSERT(thr_callstack != NULL);
42689 DUK_ASSERT(ctx != NULL);
42690
42691 /* [ ... error ] */
42692
42693 /*
42694 * Criteria for augmenting:
42695 *
42696 * - augmentation enabled in build (naturally)
42697 * - error value internal prototype chain contains the built-in
42698 * Error prototype object (i.e. 'val instanceof Error')
42699 *
42700 * Additional criteria for built-in augmenting:
42701 *
42702 * - error value is an extensible object
42703 */
42704
42705 obj = duk_get_hobject(ctx, -1);
42706 if (!obj) {
42707 DUK_DDD(DUK_DDDPRINT("value is not an object, skip both built-in and user augment"));
42708 return;
42709 }
42710 if (!duk_hobject_prototype_chain_contains(thr, obj, thr->builtins[DUK_BIDX_ERROR_PROTOTYPE], 1 /*ignore_loop*/)) {
42711 /* If the value has a prototype loop, it's critical not to
42712 * throw here. Instead, assume the value is not to be
42713 * augmented.
42714 */
42715 DUK_DDD(DUK_DDDPRINT("value is not an error instance, skip both built-in and user augment"));
42716 return;
42717 }
42718 if (DUK_HOBJECT_HAS_EXTENSIBLE(obj)) {
42719 DUK_DDD(DUK_DDDPRINT("error meets criteria, built-in augment"));
42720 duk__err_augment_builtin_create(thr, thr_callstack, c_filename, c_line, noblame_fileline, obj);
42721 } else {
42722 DUK_DDD(DUK_DDDPRINT("error does not meet criteria, no built-in augment"));
42723 }
42724
42725 /* [ ... error ] */
42726
42727#if defined(DUK_USE_ERRCREATE)
42728 duk__err_augment_user(thr, DUK_STRIDX_ERR_CREATE);
42729#endif
42730}
42731#endif /* DUK_USE_AUGMENT_ERROR_CREATE */
42732
42733/*
42734 * Augment an error at throw time; allow a user error handler (if defined)
42735 * to process/replace the error. The error to be augmented is at the
42736 * stack top.
42737 */
42738
42739#if defined(DUK_USE_AUGMENT_ERROR_THROW)
42740DUK_INTERNAL void duk_err_augment_error_throw(duk_hthread *thr) {
42741#if defined(DUK_USE_ERRTHROW)
42742 duk__err_augment_user(thr, DUK_STRIDX_ERR_THROW);
42743#endif /* DUK_USE_ERRTHROW */
42744}
42745#endif /* DUK_USE_AUGMENT_ERROR_THROW */
42746/*
42747 * Do a longjmp call, calling the fatal error handler if no
42748 * catchpoint exists.
42749 */
42750
42751/* #include duk_internal.h -> already included */
42752
42753#if defined(DUK_USE_PREFER_SIZE)
42754DUK_LOCAL void duk__uncaught_minimal(duk_hthread *thr) {
42755 (void) duk_fatal((duk_context *) thr, "uncaught error");
42756}
42757#endif
42758
42759#if 0
42760DUK_LOCAL void duk__uncaught_readable(duk_hthread *thr) {
42761 const char *summary;
42762 char buf[64];
42763
42764 summary = duk_push_string_tval_readable((duk_context *) thr, &thr->heap->lj.value1);
42765 DUK_SNPRINTF(buf, sizeof(buf), "uncaught: %s", summary);
42766 buf[sizeof(buf) - 1] = (char) 0;
42767 (void) duk_fatal((duk_context *) thr, (const char *) buf);
42768}
42769#endif
42770
42771#if !defined(DUK_USE_PREFER_SIZE)
42772DUK_LOCAL void duk__uncaught_error_aware(duk_hthread *thr) {
42773 const char *summary;
42774 char buf[64];
42775
42776 summary = duk_push_string_tval_readable_error((duk_context *) thr, &thr->heap->lj.value1);
42777 DUK_ASSERT(summary != NULL);
42778 DUK_SNPRINTF(buf, sizeof(buf), "uncaught: %s", summary);
42779 buf[sizeof(buf) - 1] = (char) 0;
42780 (void) duk_fatal((duk_context *) thr, (const char *) buf);
42781}
42782#endif
42783
42784DUK_INTERNAL void duk_err_longjmp(duk_hthread *thr) {
42785 DUK_ASSERT(thr != NULL);
42786
42787 DUK_DD(DUK_DDPRINT("longjmp error: type=%d iserror=%d value1=%!T value2=%!T",
42788 (int) thr->heap->lj.type, (int) thr->heap->lj.iserror,
42789 &thr->heap->lj.value1, &thr->heap->lj.value2));
42790
42791 /* Perform a refzero check before throwing: this catches cases where
42792 * some internal code uses no-refzero (NORZ) macro variants but an
42793 * error occurs before it has the chance to DUK_REFZERO_CHECK_xxx()
42794 * explicitly. Refzero'ed objects would otherwise remain pending
42795 * until the next refzero (which is not a big issue but still).
42796 */
42797 DUK_REFZERO_CHECK_SLOW(thr);
42798
42799#if !defined(DUK_USE_CPP_EXCEPTIONS)
42800 /* If we don't have a jmpbuf_ptr, there is little we can do except
42801 * cause a fatal error. The caller's expectation is that we never
42802 * return.
42803 *
42804 * With C++ exceptions we now just propagate an uncaught error
42805 * instead of invoking the fatal error handler. Because there's
42806 * a dummy jmpbuf for C++ exceptions now, this could be changed.
42807 */
42808 if (!thr->heap->lj.jmpbuf_ptr) {
42809 DUK_D(DUK_DPRINT("uncaught error: type=%d iserror=%d value1=%!T value2=%!T",
42810 (int) thr->heap->lj.type, (int) thr->heap->lj.iserror,
42811 &thr->heap->lj.value1, &thr->heap->lj.value2));
42812
42813#if defined(DUK_USE_PREFER_SIZE)
42814 duk__uncaught_minimal(thr);
42815#else
42816 duk__uncaught_error_aware(thr);
42817#endif
42818 DUK_UNREACHABLE();
42819 }
42820#endif /* DUK_USE_CPP_EXCEPTIONS */
42821
42822#if defined(DUK_USE_CPP_EXCEPTIONS)
42823 {
42824 duk_internal_exception exc; /* dummy */
42825 throw exc;
42826 }
42827#else /* DUK_USE_CPP_EXCEPTIONS */
42828 DUK_LONGJMP(thr->heap->lj.jmpbuf_ptr->jb);
42829#endif /* DUK_USE_CPP_EXCEPTIONS */
42830
42831 DUK_UNREACHABLE();
42832}
42833/*
42834 * Error helpers
42835 */
42836
42837/* #include duk_internal.h -> already included */
42838
42839/*
42840 * Helper to walk the thread chain and see if there is an active error
42841 * catcher. Protected calls or finally blocks aren't considered catching.
42842 */
42843
42844#if defined(DUK_USE_DEBUGGER_SUPPORT) && \
42845 (defined(DUK_USE_DEBUGGER_THROW_NOTIFY) || defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT))
42846DUK_LOCAL duk_bool_t duk__have_active_catcher(duk_hthread *thr) {
42847 /*
42848 * XXX: As noted above, a protected API call won't be counted as a
42849 * catcher. This is usually convenient, e.g. in the case of a top-
42850 * level duk_pcall(), but may not always be desirable. Perhaps add an
42851 * argument to treat them as catchers?
42852 */
42853
42854 duk_size_t i;
42855
42856 DUK_ASSERT(thr != NULL);
42857
42858 while (thr != NULL) {
42859 for (i = 0; i < thr->catchstack_top; i++) {
42860 duk_catcher *cat = thr->catchstack + i;
42861 if (DUK_CAT_HAS_CATCH_ENABLED(cat)) {
42862 return 1; /* all we need to know */
42863 }
42864 }
42865 thr = thr->resumer;
42866 }
42867 return 0;
42868}
42869#endif /* DUK_USE_DEBUGGER_SUPPORT && (DUK_USE_DEBUGGER_THROW_NOTIFY || DUK_USE_DEBUGGER_PAUSE_UNCAUGHT) */
42870
42871/*
42872 * Get prototype object for an integer error code.
42873 */
42874
42875DUK_INTERNAL duk_hobject *duk_error_prototype_from_code(duk_hthread *thr, duk_errcode_t code) {
42876 switch (code) {
42877 case DUK_ERR_EVAL_ERROR:
42878 return thr->builtins[DUK_BIDX_EVAL_ERROR_PROTOTYPE];
42879 case DUK_ERR_RANGE_ERROR:
42880 return thr->builtins[DUK_BIDX_RANGE_ERROR_PROTOTYPE];
42881 case DUK_ERR_REFERENCE_ERROR:
42882 return thr->builtins[DUK_BIDX_REFERENCE_ERROR_PROTOTYPE];
42883 case DUK_ERR_SYNTAX_ERROR:
42884 return thr->builtins[DUK_BIDX_SYNTAX_ERROR_PROTOTYPE];
42885 case DUK_ERR_TYPE_ERROR:
42886 return thr->builtins[DUK_BIDX_TYPE_ERROR_PROTOTYPE];
42887 case DUK_ERR_URI_ERROR:
42888 return thr->builtins[DUK_BIDX_URI_ERROR_PROTOTYPE];
42889 case DUK_ERR_ERROR:
42890 default:
42891 return thr->builtins[DUK_BIDX_ERROR_PROTOTYPE];
42892 }
42893}
42894
42895/*
42896 * Exposed helper for setting up heap longjmp state.
42897 */
42898
42899DUK_INTERNAL void duk_err_setup_heap_ljstate(duk_hthread *thr, duk_small_int_t lj_type) {
42900#if defined(DUK_USE_DEBUGGER_SUPPORT)
42901 /* If something is thrown with the debugger attached and nobody will
42902 * catch it, execution is paused before the longjmp, turning over
42903 * control to the debug client. This allows local state to be examined
42904 * before the stack is unwound. Errors are not intercepted when debug
42905 * message loop is active (e.g. for Eval).
42906 */
42907
42908 /* XXX: Allow customizing the pause and notify behavior at runtime
42909 * using debugger runtime flags. For now the behavior is fixed using
42910 * config options.
42911 */
42912#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY) || defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT)
42913 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap) &&
42914 !thr->heap->dbg_processing &&
42915 lj_type == DUK_LJ_TYPE_THROW) {
42916 duk_context *ctx = (duk_context *) thr;
42917 duk_bool_t fatal;
42918 duk_hobject *h_obj;
42919
42920 /* Don't intercept a DoubleError, we may have caused the initial double
42921 * fault and attempting to intercept it will cause us to be called
42922 * recursively and exhaust the C stack.
42923 */
42924 h_obj = duk_get_hobject(ctx, -1);
42925 if (h_obj == thr->builtins[DUK_BIDX_DOUBLE_ERROR]) {
42926 DUK_D(DUK_DPRINT("built-in DoubleError instance thrown, not intercepting"));
42927 goto skip_throw_intercept;
42928 }
42929
42930 DUK_D(DUK_DPRINT("throw with debugger attached, report to client"));
42931
42932 fatal = !duk__have_active_catcher(thr);
42933
42934#if defined(DUK_USE_DEBUGGER_THROW_NOTIFY)
42935 /* Report it to the debug client */
42936 duk_debug_send_throw(thr, fatal);
42937#endif
42938
42939#if defined(DUK_USE_DEBUGGER_PAUSE_UNCAUGHT)
42940 if (fatal) {
42941 DUK_D(DUK_DPRINT("throw will be fatal, halt before longjmp"));
42942 duk_debug_halt_execution(thr, 1 /*use_prev_pc*/);
42943 }
42944#endif
42945 }
42946
42947 skip_throw_intercept:
42948#endif /* DUK_USE_DEBUGGER_THROW_NOTIFY || DUK_USE_DEBUGGER_PAUSE_UNCAUGHT */
42949#endif /* DUK_USE_DEBUGGER_SUPPORT */
42950
42951 thr->heap->lj.type = lj_type;
42952
42953 DUK_ASSERT(thr->valstack_top > thr->valstack);
42954 DUK_TVAL_SET_TVAL_UPDREF(thr, &thr->heap->lj.value1, thr->valstack_top - 1); /* side effects */
42955
42956 duk_pop((duk_context *) thr);
42957}
42958/*
42959 * Create and throw an Ecmascript error object based on a code and a message.
42960 *
42961 * Used when we throw errors internally. Ecmascript generated error objects
42962 * are created by Ecmascript code, and the throwing is handled by the bytecode
42963 * executor.
42964 */
42965
42966/* #include duk_internal.h -> already included */
42967
42968/*
42969 * Create and throw an error (originating from Duktape internally)
42970 *
42971 * Push an error object on top of the stack, possibly throw augmenting
42972 * the error, and finally longjmp.
42973 *
42974 * If an error occurs while we're dealing with the current error, we might
42975 * enter an infinite recursion loop. This is prevented by detecting a
42976 * "double fault" through the heap->handling_error flag; the recursion
42977 * then stops at the second level.
42978 */
42979
42980#if defined(DUK_USE_VERBOSE_ERRORS)
42981DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code, const char *msg, const char *filename, duk_int_t line) {
42982#else
42983DUK_INTERNAL void duk_err_create_and_throw(duk_hthread *thr, duk_errcode_t code) {
42984#endif
42985 duk_context *ctx = (duk_context *) thr;
42986 duk_bool_t double_error = thr->heap->handling_error;
42987
42988#if defined(DUK_USE_VERBOSE_ERRORS)
42989 DUK_DD(DUK_DDPRINT("duk_err_create_and_throw(): code=%ld, msg=%s, filename=%s, line=%ld",
42990 (long) code, (const char *) msg,
42991 (const char *) filename, (long) line));
42992#else
42993 DUK_DD(DUK_DDPRINT("duk_err_create_and_throw(): code=%ld", (long) code));
42994#endif
42995
42996 DUK_ASSERT(thr != NULL);
42997 DUK_ASSERT(ctx != NULL);
42998
42999 thr->heap->handling_error = 1;
43000
43001 if (!double_error) {
43002 /* Allow headroom for calls during error handling (see GH-191).
43003 * We allow space for 10 additional recursions, with one extra
43004 * for, e.g. a print() call at the deepest level.
43005 */
43006 DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX);
43007 thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11;
43008 }
43009
43010 DUK_ASSERT(thr->callstack_max == DUK_CALLSTACK_DEFAULT_MAX + DUK_CALLSTACK_GROW_STEP + 11); /* just making sure */
43011
43012 /* Sync so that augmentation sees up-to-date activations, NULL
43013 * thr->ptr_curr_pc so that it's not used if side effects occur
43014 * in augmentation or longjmp handling.
43015 */
43016 duk_hthread_sync_and_null_currpc(thr);
43017
43018 /*
43019 * Create and push an error object onto the top of stack.
43020 * If a "double error" occurs, use a fixed error instance
43021 * to avoid further trouble.
43022 */
43023
43024 /* XXX: if attempt to push beyond allocated valstack, this double fault
43025 * handling fails miserably. We should really write the double error
43026 * directly to thr->heap->lj.value1 and avoid valstack use entirely.
43027 */
43028
43029 if (double_error) {
43030 if (thr->builtins[DUK_BIDX_DOUBLE_ERROR]) {
43031 DUK_D(DUK_DPRINT("double fault detected -> push built-in fixed 'double error' instance"));
43032 duk_push_hobject_bidx(ctx, DUK_BIDX_DOUBLE_ERROR);
43033 } else {
43034 DUK_D(DUK_DPRINT("double fault detected; there is no built-in fixed 'double error' instance "
43035 "-> push the error code as a number"));
43036 duk_push_int(ctx, (duk_int_t) code);
43037 }
43038 } else {
43039 /* Error object is augmented at its creation here. */
43040 duk_require_stack(ctx, 1);
43041 /* XXX: unnecessary '%s' formatting here, but cannot use
43042 * 'msg' as a format string directly.
43043 */
43044#if defined(DUK_USE_VERBOSE_ERRORS)
43045 duk_push_error_object_raw(ctx,
43046 code | DUK_ERRCODE_FLAG_NOBLAME_FILELINE,
43047 filename,
43048 line,
43049 "%s",
43050 (const char *) msg);
43051#else
43052 duk_push_error_object_raw(ctx,
43053 code | DUK_ERRCODE_FLAG_NOBLAME_FILELINE,
43054 NULL,
43055 0,
43056 NULL);
43057#endif
43058 }
43059
43060 /*
43061 * Augment error (throw time), unless double error
43062 *
43063 * Note that an alloc error may happen during error augmentation.
43064 * This may happen both when the original error is an alloc error
43065 * and when it's something else. Because any error in augmentation
43066 * must be handled correctly anyway, there's no special check for
43067 * avoiding it for alloc errors (this differs from Duktape 1.x).
43068 */
43069
43070 if (double_error) {
43071 DUK_D(DUK_DPRINT("double error: skip throw augmenting to avoid further trouble"));
43072 } else {
43073#if defined(DUK_USE_AUGMENT_ERROR_THROW)
43074 DUK_DDD(DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT (before throw augment)",
43075 (duk_tval *) duk_get_tval(ctx, -1)));
43076 duk_err_augment_error_throw(thr);
43077#endif
43078 }
43079
43080 /*
43081 * Finally, longjmp
43082 */
43083
43084 duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW);
43085
43086 thr->callstack_max = DUK_CALLSTACK_DEFAULT_MAX; /* reset callstack limit */
43087 thr->heap->handling_error = 0;
43088
43089 DUK_DDD(DUK_DDDPRINT("THROW ERROR (INTERNAL): %!iT, %!iT (after throw augment)",
43090 (duk_tval *) &thr->heap->lj.value1, (duk_tval *) &thr->heap->lj.value2));
43091
43092 duk_err_longjmp(thr);
43093 DUK_UNREACHABLE();
43094}
43095
43096/*
43097 * Helper for C function call negative return values.
43098 */
43099
43100DUK_INTERNAL void duk_error_throw_from_negative_rc(duk_hthread *thr, duk_ret_t rc) {
43101 duk_context *ctx = (duk_context *) thr;
43102
43103 DUK_ASSERT(thr != NULL);
43104 DUK_ASSERT(rc < 0);
43105
43106 /*
43107 * The __FILE__ and __LINE__ information is intentionally not used in the
43108 * creation of the error object, as it isn't useful in the tracedata. The
43109 * tracedata still contains the function which returned the negative return
43110 * code, and having the file/line of this function isn't very useful.
43111 *
43112 * The error messages for DUK_RET_xxx shorthand are intentionally very
43113 * minimal: they're only really useful for low memory targets.
43114 */
43115
43116 duk_error_raw(ctx, -rc, NULL, 0, "error (rc %ld)", (long) rc);
43117 DUK_UNREACHABLE();
43118}
43119/*
43120 * duk_hbuffer allocation and freeing.
43121 */
43122
43123/* #include duk_internal.h -> already included */
43124
43125/* Allocate a new duk_hbuffer of a certain type and return a pointer to it
43126 * (NULL on error). Write buffer data pointer to 'out_bufdata' (only if
43127 * allocation successful).
43128 */
43129DUK_INTERNAL duk_hbuffer *duk_hbuffer_alloc(duk_heap *heap, duk_size_t size, duk_small_uint_t flags, void **out_bufdata) {
43130 duk_hbuffer *res = NULL;
43131 duk_size_t header_size;
43132 duk_size_t alloc_size;
43133
43134 DUK_ASSERT(heap != NULL);
43135 DUK_ASSERT(out_bufdata != NULL);
43136
43137 DUK_DDD(DUK_DDDPRINT("allocate hbuffer"));
43138
43139 /* Size sanity check. Should not be necessary because caller is
43140 * required to check this, but we don't want to cause a segfault
43141 * if the size wraps either in duk_size_t computation or when
43142 * storing the size in a 16-bit field.
43143 */
43144 if (size > DUK_HBUFFER_MAX_BYTELEN) {
43145 DUK_D(DUK_DPRINT("hbuffer alloc failed: size too large: %ld", (long) size));
43146 return NULL; /* no need to write 'out_bufdata' */
43147 }
43148
43149 if (flags & DUK_BUF_FLAG_EXTERNAL) {
43150 header_size = sizeof(duk_hbuffer_external);
43151 alloc_size = sizeof(duk_hbuffer_external);
43152 } else if (flags & DUK_BUF_FLAG_DYNAMIC) {
43153 header_size = sizeof(duk_hbuffer_dynamic);
43154 alloc_size = sizeof(duk_hbuffer_dynamic);
43155 } else {
43156 header_size = sizeof(duk_hbuffer_fixed);
43157 alloc_size = sizeof(duk_hbuffer_fixed) + size;
43158 DUK_ASSERT(alloc_size >= sizeof(duk_hbuffer_fixed)); /* no wrapping */
43159 }
43160
43161 res = (duk_hbuffer *) DUK_ALLOC(heap, alloc_size);
43162 if (!res) {
43163 goto error;
43164 }
43165
43166 /* zero everything unless requested not to do so */
43167#if defined(DUK_USE_ZERO_BUFFER_DATA)
43168 DUK_MEMZERO((void *) res,
43169 (flags & DUK_BUF_FLAG_NOZERO) ? header_size : alloc_size);
43170#else
43171 DUK_MEMZERO((void *) res, header_size);
43172#endif
43173
43174 if (flags & DUK_BUF_FLAG_EXTERNAL) {
43176 h = (duk_hbuffer_external *) res;
43177 DUK_UNREF(h);
43178 *out_bufdata = NULL;
43179#if defined(DUK_USE_EXPLICIT_NULL_INIT)
43180#if defined(DUK_USE_HEAPPTR16)
43181/* the compressed pointer is zeroed which maps to NULL, so nothing to do. */
43182#else
43183 DUK_HBUFFER_EXTERNAL_SET_DATA_PTR(heap, h, NULL);
43184#endif
43185#endif
43186 DUK_ASSERT(DUK_HBUFFER_EXTERNAL_GET_DATA_PTR(heap, h) == NULL);
43187 } else if (flags & DUK_BUF_FLAG_DYNAMIC) {
43189 void *ptr;
43190
43191 if (size > 0) {
43192 DUK_ASSERT(!(flags & DUK_BUF_FLAG_EXTERNAL)); /* alloc external with size zero */
43193 DUK_DDD(DUK_DDDPRINT("dynamic buffer with nonzero size, alloc actual buffer"));
43194#if defined(DUK_USE_ZERO_BUFFER_DATA)
43195 ptr = DUK_ALLOC_ZEROED(heap, size);
43196#else
43197 ptr = DUK_ALLOC(heap, size);
43198#endif
43199 if (!ptr) {
43200 /* Because size > 0, NULL check is correct */
43201 goto error;
43202 }
43203 *out_bufdata = ptr;
43204
43205 DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap, h, ptr);
43206 } else {
43207 *out_bufdata = NULL;
43208#if defined(DUK_USE_EXPLICIT_NULL_INIT)
43209#if defined(DUK_USE_HEAPPTR16)
43210/* the compressed pointer is zeroed which maps to NULL, so nothing to do. */
43211#else
43212 DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(heap, h, NULL);
43213#endif
43214#endif
43215 DUK_ASSERT(DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, h) == NULL);
43216 }
43217 } else {
43218 *out_bufdata = (void *) ((duk_hbuffer_fixed *) res + 1);
43219 }
43220
43221 DUK_HBUFFER_SET_SIZE(res, size);
43222
43223 DUK_HEAPHDR_SET_TYPE(&res->hdr, DUK_HTYPE_BUFFER);
43224 if (flags & DUK_BUF_FLAG_DYNAMIC) {
43225 DUK_HBUFFER_SET_DYNAMIC(res);
43226 if (flags & DUK_BUF_FLAG_EXTERNAL) {
43227 DUK_HBUFFER_SET_EXTERNAL(res);
43228 }
43229 } else {
43230 DUK_ASSERT(!(flags & DUK_BUF_FLAG_EXTERNAL));
43231 }
43232 DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &res->hdr);
43233
43234 DUK_DDD(DUK_DDDPRINT("allocated hbuffer: %p", (void *) res));
43235 return res;
43236
43237 error:
43238 DUK_DD(DUK_DDPRINT("hbuffer allocation failed"));
43239
43240 DUK_FREE(heap, res);
43241 return NULL; /* no need to write 'out_bufdata' */
43242}
43243
43244/* For indirect allocs. */
43245
43246DUK_INTERNAL void *duk_hbuffer_get_dynalloc_ptr(duk_heap *heap, void *ud) {
43248 DUK_UNREF(heap);
43249 return (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, buf);
43250}
43251/*
43252 * duk_hbuffer operations such as resizing and inserting/appending data to
43253 * a dynamic buffer.
43254 *
43255 * Append operations append to the end of the buffer and they are relatively
43256 * efficient: the buffer is grown with a "spare" part relative to the buffer
43257 * size to minimize reallocations. Insert operations need to move existing
43258 * data forward in the buffer with memmove() and are not very efficient.
43259 * They are used e.g. by the regexp compiler to "backpatch" regexp bytecode.
43260 */
43261
43262/* #include duk_internal.h -> already included */
43263
43264/*
43265 * Resizing
43266 */
43267
43268DUK_INTERNAL void duk_hbuffer_resize(duk_hthread *thr, duk_hbuffer_dynamic *buf, duk_size_t new_size) {
43269 void *res;
43270 duk_size_t prev_size;
43271
43272 DUK_ASSERT(thr != NULL);
43273 DUK_ASSERT(buf != NULL);
43274 DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
43275 DUK_ASSERT(!DUK_HBUFFER_HAS_EXTERNAL(buf));
43276
43277 /*
43278 * Maximum size check
43279 */
43280
43281 if (new_size > DUK_HBUFFER_MAX_BYTELEN) {
43282 DUK_ERROR_RANGE(thr, "buffer too long");
43283 }
43284
43285 /*
43286 * Note: use indirect realloc variant just in case mark-and-sweep
43287 * (finalizers) might resize this same buffer during garbage
43288 * collection.
43289 */
43290
43291 res = DUK_REALLOC_INDIRECT(thr->heap, duk_hbuffer_get_dynalloc_ptr, (void *) buf, new_size);
43292 if (res != NULL || new_size == 0) {
43293 /* 'res' may be NULL if new allocation size is 0. */
43294
43295 DUK_DDD(DUK_DDDPRINT("resized dynamic buffer %p:%ld -> %p:%ld",
43296 (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, buf),
43297 (long) DUK_HBUFFER_DYNAMIC_GET_SIZE(buf),
43298 (void *) res,
43299 (long) new_size));
43300
43301 /*
43302 * The entire allocated buffer area, regardless of actual used
43303 * size, is kept zeroed in resizes for simplicity. If the buffer
43304 * is grown, zero the new part.
43305 */
43306
43307 prev_size = DUK_HBUFFER_DYNAMIC_GET_SIZE(buf);
43308 if (new_size > prev_size) {
43309 DUK_ASSERT(new_size - prev_size > 0);
43310#if defined(DUK_USE_ZERO_BUFFER_DATA)
43311 DUK_MEMZERO((void *) ((char *) res + prev_size),
43312 (duk_size_t) (new_size - prev_size));
43313#endif
43314 }
43315
43316 DUK_HBUFFER_DYNAMIC_SET_SIZE(buf, new_size);
43317 DUK_HBUFFER_DYNAMIC_SET_DATA_PTR(thr->heap, buf, res);
43318 } else {
43319 DUK_ERROR_ALLOC_FAILED(thr);
43320 }
43321
43322 DUK_ASSERT(res != NULL || new_size == 0);
43323}
43324
43325DUK_INTERNAL void duk_hbuffer_reset(duk_hthread *thr, duk_hbuffer_dynamic *buf) {
43326 DUK_ASSERT(thr != NULL);
43327 DUK_ASSERT(buf != NULL);
43328 DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(buf));
43329 DUK_ASSERT(!DUK_HBUFFER_HAS_EXTERNAL(buf));
43330
43331 duk_hbuffer_resize(thr, buf, 0);
43332}
43333/* #include duk_internal.h -> already included */
43334
43335#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
43336DUK_INTERNAL duk_uint_t duk_hbufobj_clamp_bytelength(duk_hbufobj *h_bufobj, duk_uint_t len) {
43337 duk_uint_t buf_size;
43338 duk_uint_t buf_avail;
43339
43340 DUK_ASSERT(h_bufobj != NULL);
43341 DUK_ASSERT(h_bufobj->buf != NULL);
43342
43343 buf_size = (duk_uint_t) DUK_HBUFFER_GET_SIZE(h_bufobj->buf);
43344 if (h_bufobj->offset > buf_size) {
43345 /* Slice starting point is beyond current length. */
43346 return 0;
43347 }
43348 buf_avail = buf_size - h_bufobj->offset;
43349
43350 return buf_avail >= len ? len : buf_avail;
43351}
43352#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
43353/*
43354 * duk_heap allocation and freeing.
43355 */
43356
43357/* #include duk_internal.h -> already included */
43358
43359#if defined(DUK_USE_ROM_STRINGS)
43360/* Fixed seed value used with ROM strings. */
43361#define DUK__FIXED_HASH_SEED 0xabcd1234
43362#endif
43363
43364/*
43365 * Free a heap object.
43366 *
43367 * Free heap object and its internal (non-heap) pointers. Assumes that
43368 * caller has removed the object from heap allocated list or the string
43369 * intern table, and any weak references (which strings may have) have
43370 * been already dealt with.
43371 */
43372
43373DUK_INTERNAL void duk_free_hobject(duk_heap *heap, duk_hobject *h) {
43374 DUK_ASSERT(heap != NULL);
43375 DUK_ASSERT(h != NULL);
43376
43377 DUK_FREE(heap, DUK_HOBJECT_GET_PROPS(heap, h));
43378
43379 if (DUK_HOBJECT_IS_COMPFUNC(h)) {
43380 duk_hcompfunc *f = (duk_hcompfunc *) h;
43381 DUK_UNREF(f);
43382 /* Currently nothing to free; 'data' is a heap object */
43383 } else if (DUK_HOBJECT_IS_NATFUNC(h)) {
43384 duk_hnatfunc *f = (duk_hnatfunc *) h;
43385 DUK_UNREF(f);
43386 /* Currently nothing to free */
43387 } else if (DUK_HOBJECT_IS_THREAD(h)) {
43388 duk_hthread *t = (duk_hthread *) h;
43389 DUK_FREE(heap, t->valstack);
43390 DUK_FREE(heap, t->callstack);
43391 DUK_FREE(heap, t->catchstack);
43392 /* Don't free h->resumer because it exists in the heap.
43393 * Callstack entries also contain function pointers which
43394 * are not freed for the same reason.
43395 */
43396
43397 /* XXX: with 'caller' property the callstack would need
43398 * to be unwound to update the 'caller' properties of
43399 * functions in the callstack.
43400 */
43401 }
43402 DUK_FREE(heap, (void *) h);
43403}
43404
43405DUK_INTERNAL void duk_free_hbuffer(duk_heap *heap, duk_hbuffer *h) {
43406 DUK_ASSERT(heap != NULL);
43407 DUK_ASSERT(h != NULL);
43408
43409 if (DUK_HBUFFER_HAS_DYNAMIC(h) && !DUK_HBUFFER_HAS_EXTERNAL(h)) {
43411 DUK_DDD(DUK_DDDPRINT("free dynamic buffer %p", (void *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, g)));
43412 DUK_FREE(heap, DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(heap, g));
43413 }
43414 DUK_FREE(heap, (void *) h);
43415}
43416
43417DUK_INTERNAL void duk_free_hstring(duk_heap *heap, duk_hstring *h) {
43418 DUK_ASSERT(heap != NULL);
43419 DUK_ASSERT(h != NULL);
43420
43421 DUK_UNREF(heap);
43422 DUK_UNREF(h);
43423
43424#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_FREE)
43425 if (DUK_HSTRING_HAS_EXTDATA(h)) {
43426 DUK_DDD(DUK_DDDPRINT("free extstr: hstring %!O, extdata: %p",
43427 h, DUK_HSTRING_GET_EXTDATA((duk_hstring_external *) h)));
43428 DUK_USE_EXTSTR_FREE(heap->heap_udata, (const void *) DUK_HSTRING_GET_EXTDATA((duk_hstring_external *) h));
43429 }
43430#endif
43431 DUK_FREE(heap, (void *) h);
43432}
43433
43434DUK_INTERNAL void duk_heap_free_heaphdr_raw(duk_heap *heap, duk_heaphdr *hdr) {
43435 DUK_ASSERT(heap);
43436 DUK_ASSERT(hdr);
43437
43438 DUK_DDD(DUK_DDDPRINT("free heaphdr %p, htype %ld", (void *) hdr, (long) DUK_HEAPHDR_GET_TYPE(hdr)));
43439
43440 switch (DUK_HEAPHDR_GET_TYPE(hdr)) {
43441 case DUK_HTYPE_STRING:
43442 duk_free_hstring(heap, (duk_hstring *) hdr);
43443 break;
43444 case DUK_HTYPE_OBJECT:
43445 duk_free_hobject(heap, (duk_hobject *) hdr);
43446 break;
43447 case DUK_HTYPE_BUFFER:
43448 duk_free_hbuffer(heap, (duk_hbuffer *) hdr);
43449 break;
43450 default:
43451 DUK_UNREACHABLE();
43452 }
43453
43454}
43455
43456/*
43457 * Free the heap.
43458 *
43459 * Frees heap-related non-heap-tracked allocations such as the
43460 * string intern table; then frees the heap allocated objects;
43461 * and finally frees the heap structure itself. Reference counts
43462 * and GC markers are ignored (and not updated) in this process,
43463 * and finalizers won't be called.
43464 *
43465 * The heap pointer and heap object pointers must not be used
43466 * after this call.
43467 */
43468
43469DUK_LOCAL void duk__free_allocated(duk_heap *heap) {
43470 duk_heaphdr *curr;
43471 duk_heaphdr *next;
43472
43473 curr = heap->heap_allocated;
43474 while (curr) {
43475 /* We don't log or warn about freeing zero refcount objects
43476 * because they may happen with finalizer processing.
43477 */
43478
43479 DUK_DDD(DUK_DDDPRINT("FINALFREE (allocated): %!iO",
43480 (duk_heaphdr *) curr));
43481 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
43482 duk_heap_free_heaphdr_raw(heap, curr);
43483 curr = next;
43484 }
43485}
43486
43487#if defined(DUK_USE_REFERENCE_COUNTING)
43488DUK_LOCAL void duk__free_refzero_list(duk_heap *heap) {
43489 duk_heaphdr *curr;
43490 duk_heaphdr *next;
43491
43492 curr = heap->refzero_list;
43493 while (curr) {
43494 DUK_DDD(DUK_DDDPRINT("FINALFREE (refzero_list): %!iO",
43495 (duk_heaphdr *) curr));
43496 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
43497 duk_heap_free_heaphdr_raw(heap, curr);
43498 curr = next;
43499 }
43500}
43501#endif
43502
43503DUK_LOCAL void duk__free_markandsweep_finalize_list(duk_heap *heap) {
43504 duk_heaphdr *curr;
43505 duk_heaphdr *next;
43506
43507 curr = heap->finalize_list;
43508 while (curr) {
43509 DUK_DDD(DUK_DDDPRINT("FINALFREE (finalize_list): %!iO",
43510 (duk_heaphdr *) curr));
43511 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
43512 duk_heap_free_heaphdr_raw(heap, curr);
43513 curr = next;
43514 }
43515}
43516
43517DUK_LOCAL void duk__free_stringtable(duk_heap *heap) {
43518 /* strings are only tracked by stringtable */
43519 duk_heap_free_strtab(heap);
43520}
43521
43522#if defined(DUK_USE_FINALIZER_SUPPORT)
43523DUK_LOCAL void duk__free_run_finalizers(duk_heap *heap) {
43524 duk_hthread *thr;
43525 duk_heaphdr *curr;
43526 duk_uint_t round_no;
43527 duk_size_t count_all;
43528 duk_size_t count_finalized;
43529 duk_size_t curr_limit;
43530
43531 DUK_ASSERT(heap != NULL);
43532 DUK_ASSERT(heap->heap_thread != NULL);
43533
43534#if defined(DUK_USE_REFERENCE_COUNTING)
43535 DUK_ASSERT(heap->refzero_list == NULL); /* refzero not running -> must be empty */
43536#endif
43537 DUK_ASSERT(heap->finalize_list == NULL); /* mark-and-sweep not running -> must be empty */
43538
43539 /* XXX: here again finalizer thread is the heap_thread which needs
43540 * to be coordinated with finalizer thread fixes.
43541 */
43542 thr = heap->heap_thread;
43543 DUK_ASSERT(thr != NULL);
43544
43545 /* Prevent mark-and-sweep for the pending finalizers, also prevents
43546 * refzero handling from moving objects away from the heap_allocated
43547 * list. (The flag meaning is slightly abused here.)
43548 */
43549 DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap));
43550 DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap);
43551
43552 curr_limit = 0; /* suppress warning, not used */
43553 for (round_no = 0; ; round_no++) {
43554 curr = heap->heap_allocated;
43555 count_all = 0;
43556 count_finalized = 0;
43557 while (curr) {
43558 count_all++;
43559 if (DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT) {
43560 /* Only objects in heap_allocated may have finalizers. Check that
43561 * the object itself has a _Finalizer property (own or inherited)
43562 * so that we don't execute finalizers for e.g. Proxy objects.
43563 */
43564 DUK_ASSERT(thr != NULL);
43565 DUK_ASSERT(curr != NULL);
43566
43567 if (duk_hobject_hasprop_raw(thr, (duk_hobject *) curr, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) {
43568 if (!DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) curr)) {
43569 DUK_ASSERT(DUK_HEAP_HAS_FINALIZER_NORESCUE(heap)); /* maps to finalizer 2nd argument */
43570 duk_hobject_run_finalizer(thr, (duk_hobject *) curr);
43571 count_finalized++;
43572 }
43573 }
43574 }
43575 curr = DUK_HEAPHDR_GET_NEXT(heap, curr);
43576 }
43577
43578 /* Each round of finalizer execution may spawn new finalizable objects
43579 * which is normal behavior for some applications. Allow multiple
43580 * rounds of finalization, but use a shrinking limit based on the
43581 * first round to detect the case where a runaway finalizer creates
43582 * an unbounded amount of new finalizable objects. Finalizer rescue
43583 * is not supported: the semantics are unclear because most of the
43584 * objects being finalized here are already reachable. The finalizer
43585 * is given a boolean to indicate that rescue is not possible.
43586 *
43587 * See discussion in: https://github.com/svaarala/duktape/pull/473
43588 */
43589
43590 if (round_no == 0) {
43591 /* Cannot wrap: each object is at least 8 bytes so count is
43592 * at most 1/8 of that.
43593 */
43594 curr_limit = count_all * 2;
43595 } else {
43596 curr_limit = (curr_limit * 3) / 4; /* Decrease by 25% every round */
43597 }
43598 DUK_D(DUK_DPRINT("finalizer round %ld complete, %ld objects, tried to execute %ld finalizers, current limit is %ld",
43599 (long) round_no, (long) count_all, (long) count_finalized, (long) curr_limit));
43600
43601 if (count_finalized == 0) {
43602 DUK_D(DUK_DPRINT("no more finalizable objects, forced finalization finished"));
43603 break;
43604 }
43605 if (count_finalized >= curr_limit) {
43606 DUK_D(DUK_DPRINT("finalizer count above limit, potentially runaway finalizer; skip remaining finalizers"));
43607 break;
43608 }
43609 }
43610
43611 DUK_ASSERT(DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap));
43612 DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap);
43613}
43614#endif /* DUK_USE_FINALIZER_SUPPORT */
43615
43616DUK_INTERNAL void duk_heap_free(duk_heap *heap) {
43617 DUK_D(DUK_DPRINT("free heap: %p", (void *) heap));
43618
43619#if defined(DUK_USE_DEBUG)
43620 duk_heap_dump_strtab(heap);
43621#endif
43622
43623#if defined(DUK_USE_DEBUGGER_SUPPORT)
43624 /* Detach a debugger if attached (can be called multiple times)
43625 * safely.
43626 */
43627 /* XXX: Add a flag to reject an attempt to re-attach? Otherwise
43628 * the detached callback may immediately reattach.
43629 */
43630 duk_debug_do_detach(heap);
43631#endif
43632
43633 /* Execute finalizers before freeing the heap, even for reachable
43634 * objects, and regardless of whether or not mark-and-sweep is
43635 * enabled. This gives finalizers the chance to free any native
43636 * resources like file handles, allocations made outside Duktape,
43637 * etc. This is quite tricky to get right, so that all finalizer
43638 * guarantees are honored.
43639 *
43640 * XXX: this perhaps requires an execution time limit.
43641 */
43642 DUK_D(DUK_DPRINT("execute finalizers before freeing heap"));
43643 /* Run mark-and-sweep a few times just in case (unreachable object
43644 * finalizers run already here). The last round must rescue objects
43645 * from the previous round without running any more finalizers. This
43646 * ensures rescued objects get their FINALIZED flag cleared so that
43647 * their finalizer is called once more in forced finalization to
43648 * satisfy finalizer guarantees. However, we don't want to run any
43649 * more finalizer because that'd required one more loop, and so on.
43650 */
43651 DUK_D(DUK_DPRINT("forced gc #1 in heap destruction"));
43652 duk_heap_mark_and_sweep(heap, 0);
43653 DUK_D(DUK_DPRINT("forced gc #2 in heap destruction"));
43654 duk_heap_mark_and_sweep(heap, 0);
43655 DUK_D(DUK_DPRINT("forced gc #3 in heap destruction (don't run finalizers)"));
43656 duk_heap_mark_and_sweep(heap, DUK_MS_FLAG_SKIP_FINALIZERS); /* skip finalizers; queue finalizable objects to heap_allocated */
43657
43658#if defined(DUK_USE_FINALIZER_SUPPORT)
43659 DUK_HEAP_SET_FINALIZER_NORESCUE(heap); /* rescue no longer supported */
43660 duk__free_run_finalizers(heap);
43661#endif /* DUK_USE_FINALIZER_SUPPORT */
43662
43663 /* Note: heap->heap_thread, heap->curr_thread, and heap->heap_object
43664 * are on the heap allocated list.
43665 */
43666
43667 DUK_D(DUK_DPRINT("freeing heap objects of heap: %p", (void *) heap));
43668 duk__free_allocated(heap);
43669
43670#if defined(DUK_USE_REFERENCE_COUNTING)
43671 DUK_D(DUK_DPRINT("freeing refzero list of heap: %p", (void *) heap));
43672 duk__free_refzero_list(heap);
43673#endif
43674
43675 DUK_D(DUK_DPRINT("freeing mark-and-sweep finalize list of heap: %p", (void *) heap));
43676 duk__free_markandsweep_finalize_list(heap);
43677
43678 DUK_D(DUK_DPRINT("freeing string table of heap: %p", (void *) heap));
43679 duk__free_stringtable(heap);
43680
43681 DUK_D(DUK_DPRINT("freeing heap structure: %p", (void *) heap));
43682 heap->free_func(heap->heap_udata, heap);
43683}
43684
43685/*
43686 * Allocate a heap.
43687 *
43688 * String table is initialized with built-in strings from genbuiltins.py,
43689 * either by dynamically creating the strings or by referring to ROM strings.
43690 */
43691
43692#if defined(DUK_USE_ROM_STRINGS)
43693DUK_LOCAL duk_bool_t duk__init_heap_strings(duk_heap *heap) {
43694#if defined(DUK_USE_ASSERTIONS)
43695 duk_small_uint_t i;
43696#endif
43697
43698 /* With ROM-based strings, heap->strs[] and thr->strs[] are omitted
43699 * so nothing to initialize for strs[].
43700 */
43701
43702#if defined(DUK_USE_ASSERTIONS)
43703 for (i = 0; i < sizeof(duk_rom_strings) / sizeof(const duk_hstring *); i++) {
43704 duk_uint32_t hash;
43705 const duk_hstring *h;
43706 h = duk_rom_strings[i];
43707 DUK_ASSERT(h != NULL);
43708 hash = duk_heap_hashstring(heap, (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
43709 DUK_DD(DUK_DDPRINT("duk_rom_strings[%d] -> hash 0x%08lx, computed 0x%08lx",
43710 (int) i, (unsigned long) DUK_HSTRING_GET_HASH(h), (unsigned long) hash));
43711 DUK_ASSERT(hash == (duk_uint32_t) DUK_HSTRING_GET_HASH(h));
43712 }
43713#endif
43714 return 1;
43715}
43716#else /* DUK_USE_ROM_STRINGS */
43717
43718DUK_LOCAL duk_bool_t duk__init_heap_strings(duk_heap *heap) {
43719 duk_bitdecoder_ctx bd_ctx;
43720 duk_bitdecoder_ctx *bd = &bd_ctx; /* convenience */
43721 duk_small_uint_t i;
43722
43723 DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
43724 bd->data = (const duk_uint8_t *) duk_strings_data;
43725 bd->length = (duk_size_t) DUK_STRDATA_DATA_LENGTH;
43726
43727 for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
43728 duk_uint8_t tmp[DUK_STRDATA_MAX_STRLEN];
43729 duk_small_uint_t len;
43730 duk_hstring *h;
43731
43732 len = duk_bd_decode_bitpacked_string(bd, tmp);
43733
43734 /* No need to length check string: it will never exceed even
43735 * the 16-bit length maximum.
43736 */
43737 DUK_ASSERT(len <= 0xffffUL);
43738 DUK_DDD(DUK_DDDPRINT("intern built-in string %ld", (long) i));
43739 h = duk_heap_string_intern(heap, tmp, len);
43740 if (!h) {
43741 goto error;
43742 }
43743 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h));
43744
43745 /* Special flags checks. Since these strings are always
43746 * reachable and a string cannot appear twice in the string
43747 * table, there's no need to check/set these flags elsewhere.
43748 * The 'internal' flag is set by string intern code.
43749 */
43750 if (i == DUK_STRIDX_EVAL || i == DUK_STRIDX_LC_ARGUMENTS) {
43751 DUK_HSTRING_SET_EVAL_OR_ARGUMENTS(h);
43752 }
43753 if (i >= DUK_STRIDX_START_RESERVED && i < DUK_STRIDX_END_RESERVED) {
43754 DUK_HSTRING_SET_RESERVED_WORD(h);
43755 if (i >= DUK_STRIDX_START_STRICT_RESERVED) {
43756 DUK_HSTRING_SET_STRICT_RESERVED_WORD(h);
43757 }
43758 }
43759
43760 DUK_DDD(DUK_DDDPRINT("interned: %!O", (duk_heaphdr *) h));
43761
43762 /* XXX: The incref macro takes a thread pointer but doesn't
43763 * use it right now.
43764 */
43765 DUK_HSTRING_INCREF(_never_referenced_, h);
43766
43767#if defined(DUK_USE_HEAPPTR16)
43768 heap->strs16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
43769#else
43770 heap->strs[i] = h;
43771#endif
43772 }
43773
43774 return 1;
43775
43776 error:
43777 return 0;
43778}
43779#endif /* DUK_USE_ROM_STRINGS */
43780
43781DUK_LOCAL duk_bool_t duk__init_heap_thread(duk_heap *heap) {
43782 duk_hthread *thr;
43783
43784 DUK_DD(DUK_DDPRINT("heap init: alloc heap thread"));
43785 thr = duk_hthread_alloc(heap,
43786 DUK_HOBJECT_FLAG_EXTENSIBLE |
43787 DUK_HOBJECT_FLAG_THREAD |
43788 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_THREAD));
43789 if (!thr) {
43790 DUK_D(DUK_DPRINT("failed to alloc heap_thread"));
43791 return 0;
43792 }
43793 thr->state = DUK_HTHREAD_STATE_INACTIVE;
43794#if defined(DUK_USE_ROM_STRINGS)
43795 /* No strs[] pointer. */
43796#else /* DUK_USE_ROM_STRINGS */
43797#if defined(DUK_USE_HEAPPTR16)
43798 thr->strs16 = heap->strs16;
43799#else
43800 thr->strs = heap->strs;
43801#endif
43802#endif /* DUK_USE_ROM_STRINGS */
43803
43804 heap->heap_thread = thr;
43805 DUK_HTHREAD_INCREF(thr, thr); /* Note: first argument not really used */
43806
43807 /* 'thr' is now reachable */
43808
43809 if (!duk_hthread_init_stacks(heap, thr)) {
43810 return 0;
43811 }
43812
43813 /* XXX: this may now fail, and is not handled correctly */
43814 duk_hthread_create_builtin_objects(thr);
43815
43816 /* default prototype (Note: 'thr' must be reachable) */
43817 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) thr, thr->builtins[DUK_BIDX_THREAD_PROTOTYPE]);
43818
43819 return 1;
43820}
43821
43822#if defined(DUK_USE_DEBUG)
43823#define DUK__DUMPSZ(t) do { \
43824 DUK_D(DUK_DPRINT("" #t "=%ld", (long) sizeof(t))); \
43825 } while (0)
43826
43827/* These is not 100% because format would need to be non-portable "long long".
43828 * Also print out as doubles to catch cases where the "long" type is not wide
43829 * enough; the limits will then not be printed accurately but the magnitude
43830 * will be correct.
43831 */
43832#define DUK__DUMPLM_SIGNED_RAW(t,a,b) do { \
43833 DUK_D(DUK_DPRINT(t "=[%ld,%ld]=[%lf,%lf]", \
43834 (long) (a), (long) (b), \
43835 (double) (a), (double) (b))); \
43836 } while (0)
43837#define DUK__DUMPLM_UNSIGNED_RAW(t,a,b) do { \
43838 DUK_D(DUK_DPRINT(t "=[%lu,%lu]=[%lf,%lf]", \
43839 (unsigned long) (a), (unsigned long) (b), \
43840 (double) (a), (double) (b))); \
43841 } while (0)
43842#define DUK__DUMPLM_SIGNED(t) do { \
43843 DUK__DUMPLM_SIGNED_RAW("DUK_" #t "_{MIN,MAX}", DUK_##t##_MIN, DUK_##t##_MAX); \
43844 } while (0)
43845#define DUK__DUMPLM_UNSIGNED(t) do { \
43846 DUK__DUMPLM_UNSIGNED_RAW("DUK_" #t "_{MIN,MAX}", DUK_##t##_MIN, DUK_##t##_MAX); \
43847 } while (0)
43848
43849DUK_LOCAL void duk__dump_type_sizes(void) {
43850 DUK_D(DUK_DPRINT("sizeof()"));
43851
43852 /* basic platform types */
43853 DUK__DUMPSZ(char);
43854 DUK__DUMPSZ(short);
43855 DUK__DUMPSZ(int);
43856 DUK__DUMPSZ(long);
43857 DUK__DUMPSZ(double);
43858 DUK__DUMPSZ(void *);
43859 DUK__DUMPSZ(size_t);
43860
43861 /* basic types from duk_features.h */
43862 DUK__DUMPSZ(duk_uint8_t);
43863 DUK__DUMPSZ(duk_int8_t);
43864 DUK__DUMPSZ(duk_uint16_t);
43865 DUK__DUMPSZ(duk_int16_t);
43866 DUK__DUMPSZ(duk_uint32_t);
43867 DUK__DUMPSZ(duk_int32_t);
43868 DUK__DUMPSZ(duk_uint64_t);
43869 DUK__DUMPSZ(duk_int64_t);
43870 DUK__DUMPSZ(duk_uint_least8_t);
43871 DUK__DUMPSZ(duk_int_least8_t);
43872 DUK__DUMPSZ(duk_uint_least16_t);
43873 DUK__DUMPSZ(duk_int_least16_t);
43874 DUK__DUMPSZ(duk_uint_least32_t);
43875 DUK__DUMPSZ(duk_int_least32_t);
43876#if defined(DUK_USE_64BIT_OPS)
43877 DUK__DUMPSZ(duk_uint_least64_t);
43878 DUK__DUMPSZ(duk_int_least64_t);
43879#endif
43880 DUK__DUMPSZ(duk_uint_fast8_t);
43881 DUK__DUMPSZ(duk_int_fast8_t);
43882 DUK__DUMPSZ(duk_uint_fast16_t);
43883 DUK__DUMPSZ(duk_int_fast16_t);
43884 DUK__DUMPSZ(duk_uint_fast32_t);
43885 DUK__DUMPSZ(duk_int_fast32_t);
43886#if defined(DUK_USE_64BIT_OPS)
43887 DUK__DUMPSZ(duk_uint_fast64_t);
43888 DUK__DUMPSZ(duk_int_fast64_t);
43889#endif
43890 DUK__DUMPSZ(duk_uintptr_t);
43891 DUK__DUMPSZ(duk_intptr_t);
43892 DUK__DUMPSZ(duk_uintmax_t);
43893 DUK__DUMPSZ(duk_intmax_t);
43894 DUK__DUMPSZ(duk_double_t);
43895
43896 /* important chosen base types */
43897 DUK__DUMPSZ(duk_int_t);
43898 DUK__DUMPSZ(duk_uint_t);
43899 DUK__DUMPSZ(duk_int_fast_t);
43900 DUK__DUMPSZ(duk_uint_fast_t);
43901 DUK__DUMPSZ(duk_small_int_t);
43902 DUK__DUMPSZ(duk_small_uint_t);
43903 DUK__DUMPSZ(duk_small_int_fast_t);
43904 DUK__DUMPSZ(duk_small_uint_fast_t);
43905
43906 /* some derived types */
43907 DUK__DUMPSZ(duk_codepoint_t);
43908 DUK__DUMPSZ(duk_ucodepoint_t);
43909 DUK__DUMPSZ(duk_idx_t);
43910 DUK__DUMPSZ(duk_errcode_t);
43911 DUK__DUMPSZ(duk_uarridx_t);
43912
43913 /* tval */
43914 DUK__DUMPSZ(duk_double_union);
43915 DUK__DUMPSZ(duk_tval);
43916
43917 /* structs from duk_forwdecl.h */
43918 DUK__DUMPSZ(duk_jmpbuf); /* just one 'int' for C++ exceptions */
43919 DUK__DUMPSZ(duk_heaphdr);
43920 DUK__DUMPSZ(duk_heaphdr_string);
43921 DUK__DUMPSZ(duk_hstring);
43922 DUK__DUMPSZ(duk_hstring_external);
43923 DUK__DUMPSZ(duk_hobject);
43924 DUK__DUMPSZ(duk_harray);
43925 DUK__DUMPSZ(duk_hcompfunc);
43926 DUK__DUMPSZ(duk_hnatfunc);
43927 DUK__DUMPSZ(duk_hthread);
43928#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
43929 DUK__DUMPSZ(duk_hbufobj);
43930#endif
43931 DUK__DUMPSZ(duk_hbuffer);
43932 DUK__DUMPSZ(duk_hbuffer_fixed);
43933 DUK__DUMPSZ(duk_hbuffer_dynamic);
43934 DUK__DUMPSZ(duk_hbuffer_external);
43935 DUK__DUMPSZ(duk_propaccessor);
43936 DUK__DUMPSZ(duk_propvalue);
43937 DUK__DUMPSZ(duk_propdesc);
43938 DUK__DUMPSZ(duk_heap);
43939#if defined(DUK_USE_STRTAB_CHAIN)
43940 DUK__DUMPSZ(duk_strtab_entry);
43941#endif
43942 DUK__DUMPSZ(duk_activation);
43943 DUK__DUMPSZ(duk_catcher);
43944 DUK__DUMPSZ(duk_strcache);
43945 DUK__DUMPSZ(duk_ljstate);
43946 DUK__DUMPSZ(duk_fixedbuffer);
43947 DUK__DUMPSZ(duk_bitdecoder_ctx);
43948 DUK__DUMPSZ(duk_bitencoder_ctx);
43949 DUK__DUMPSZ(duk_token);
43950 DUK__DUMPSZ(duk_re_token);
43951 DUK__DUMPSZ(duk_lexer_point);
43952 DUK__DUMPSZ(duk_lexer_ctx);
43953 DUK__DUMPSZ(duk_compiler_instr);
43954 DUK__DUMPSZ(duk_compiler_func);
43955 DUK__DUMPSZ(duk_compiler_ctx);
43956 DUK__DUMPSZ(duk_re_matcher_ctx);
43957 DUK__DUMPSZ(duk_re_compiler_ctx);
43958}
43959DUK_LOCAL void duk__dump_type_limits(void) {
43960 DUK_D(DUK_DPRINT("limits"));
43961
43962 /* basic types */
43963 DUK__DUMPLM_SIGNED(INT8);
43964 DUK__DUMPLM_UNSIGNED(UINT8);
43965 DUK__DUMPLM_SIGNED(INT_FAST8);
43966 DUK__DUMPLM_UNSIGNED(UINT_FAST8);
43967 DUK__DUMPLM_SIGNED(INT_LEAST8);
43968 DUK__DUMPLM_UNSIGNED(UINT_LEAST8);
43969 DUK__DUMPLM_SIGNED(INT16);
43970 DUK__DUMPLM_UNSIGNED(UINT16);
43971 DUK__DUMPLM_SIGNED(INT_FAST16);
43972 DUK__DUMPLM_UNSIGNED(UINT_FAST16);
43973 DUK__DUMPLM_SIGNED(INT_LEAST16);
43974 DUK__DUMPLM_UNSIGNED(UINT_LEAST16);
43975 DUK__DUMPLM_SIGNED(INT32);
43976 DUK__DUMPLM_UNSIGNED(UINT32);
43977 DUK__DUMPLM_SIGNED(INT_FAST32);
43978 DUK__DUMPLM_UNSIGNED(UINT_FAST32);
43979 DUK__DUMPLM_SIGNED(INT_LEAST32);
43980 DUK__DUMPLM_UNSIGNED(UINT_LEAST32);
43981#if defined(DUK_USE_64BIT_OPS)
43982 DUK__DUMPLM_SIGNED(INT64);
43983 DUK__DUMPLM_UNSIGNED(UINT64);
43984 DUK__DUMPLM_SIGNED(INT_FAST64);
43985 DUK__DUMPLM_UNSIGNED(UINT_FAST64);
43986 DUK__DUMPLM_SIGNED(INT_LEAST64);
43987 DUK__DUMPLM_UNSIGNED(UINT_LEAST64);
43988#endif
43989 DUK__DUMPLM_SIGNED(INTPTR);
43990 DUK__DUMPLM_UNSIGNED(UINTPTR);
43991 DUK__DUMPLM_SIGNED(INTMAX);
43992 DUK__DUMPLM_UNSIGNED(UINTMAX);
43993
43994 /* derived types */
43995 DUK__DUMPLM_SIGNED(INT);
43996 DUK__DUMPLM_UNSIGNED(UINT);
43997 DUK__DUMPLM_SIGNED(INT_FAST);
43998 DUK__DUMPLM_UNSIGNED(UINT_FAST);
43999 DUK__DUMPLM_SIGNED(SMALL_INT);
44000 DUK__DUMPLM_UNSIGNED(SMALL_UINT);
44001 DUK__DUMPLM_SIGNED(SMALL_INT_FAST);
44002 DUK__DUMPLM_UNSIGNED(SMALL_UINT_FAST);
44003}
44004
44005DUK_LOCAL void duk__dump_misc_options(void) {
44006 DUK_D(DUK_DPRINT("DUK_VERSION: %ld", (long) DUK_VERSION));
44007 DUK_D(DUK_DPRINT("DUK_GIT_DESCRIBE: %s", DUK_GIT_DESCRIBE));
44008 DUK_D(DUK_DPRINT("OS string: %s", DUK_USE_OS_STRING));
44009 DUK_D(DUK_DPRINT("architecture string: %s", DUK_USE_ARCH_STRING));
44010 DUK_D(DUK_DPRINT("compiler string: %s", DUK_USE_COMPILER_STRING));
44011 DUK_D(DUK_DPRINT("debug level: %ld", (long) DUK_USE_DEBUG_LEVEL));
44012#if defined(DUK_USE_PACKED_TVAL)
44013 DUK_D(DUK_DPRINT("DUK_USE_PACKED_TVAL: yes"));
44014#else
44015 DUK_D(DUK_DPRINT("DUK_USE_PACKED_TVAL: no"));
44016#endif
44017#if defined(DUK_USE_VARIADIC_MACROS)
44018 DUK_D(DUK_DPRINT("DUK_USE_VARIADIC_MACROS: yes"));
44019#else
44020 DUK_D(DUK_DPRINT("DUK_USE_VARIADIC_MACROS: no"));
44021#endif
44022#if defined(DUK_USE_INTEGER_LE)
44023 DUK_D(DUK_DPRINT("integer endianness: little"));
44024#elif defined(DUK_USE_INTEGER_ME)
44025 DUK_D(DUK_DPRINT("integer endianness: mixed"));
44026#elif defined(DUK_USE_INTEGER_BE)
44027 DUK_D(DUK_DPRINT("integer endianness: big"));
44028#else
44029 DUK_D(DUK_DPRINT("integer endianness: ???"));
44030#endif
44031#if defined(DUK_USE_DOUBLE_LE)
44032 DUK_D(DUK_DPRINT("IEEE double endianness: little"));
44033#elif defined(DUK_USE_DOUBLE_ME)
44034 DUK_D(DUK_DPRINT("IEEE double endianness: mixed"));
44035#elif defined(DUK_USE_DOUBLE_BE)
44036 DUK_D(DUK_DPRINT("IEEE double endianness: big"));
44037#else
44038 DUK_D(DUK_DPRINT("IEEE double endianness: ???"));
44039#endif
44040}
44041#endif /* DUK_USE_DEBUG */
44042
44043DUK_INTERNAL
44044duk_heap *duk_heap_alloc(duk_alloc_function alloc_func,
44045 duk_realloc_function realloc_func,
44046 duk_free_function free_func,
44047 void *heap_udata,
44048 duk_fatal_function fatal_func) {
44049 duk_heap *res = NULL;
44050
44051 DUK_D(DUK_DPRINT("allocate heap"));
44052
44053 /*
44054 * Debug dump type sizes
44055 */
44056
44057#if defined(DUK_USE_DEBUG)
44058 duk__dump_misc_options();
44059 duk__dump_type_sizes();
44060 duk__dump_type_limits();
44061#endif
44062
44063 /*
44064 * If selftests enabled, run them as early as possible.
44065 */
44066
44067#if defined(DUK_USE_SELF_TESTS)
44068 if (duk_selftest_run_tests(alloc_func, realloc_func, free_func, heap_udata) > 0) {
44069 fatal_func(heap_udata, "self test(s) failed");
44070 }
44071#endif
44072
44073 /*
44074 * Important assert-like checks that should be enabled even
44075 * when assertions are otherwise not enabled.
44076 */
44077
44078#if defined(DUK_USE_EXEC_REGCONST_OPTIMIZE)
44079 /* Can't check sizeof() using preprocessor so explicit check.
44080 * This will be optimized away in practice; unfortunately a
44081 * warning is generated on some compilers as a result.
44082 */
44083#if defined(DUK_USE_PACKED_TVAL)
44084 if (sizeof(duk_tval) != 8) {
44085#else
44086 if (sizeof(duk_tval) != 16) {
44087#endif
44088 fatal_func(heap_udata, "sizeof(duk_tval) not 8 or 16, cannot use DUK_USE_EXEC_REGCONST_OPTIMIZE option");
44089 }
44090#endif /* DUK_USE_EXEC_REGCONST_OPTIMIZE */
44091
44092 /*
44093 * Computed values (e.g. INFINITY)
44094 */
44095
44096#if defined(DUK_USE_COMPUTED_NAN)
44097 do {
44098 /* Workaround for some exotic platforms where NAN is missing
44099 * and the expression (0.0 / 0.0) does NOT result in a NaN.
44100 * Such platforms use the global 'duk_computed_nan' which must
44101 * be initialized at runtime. Use 'volatile' to ensure that
44102 * the compiler will actually do the computation and not try
44103 * to do constant folding which might result in the original
44104 * problem.
44105 */
44106 volatile double dbl1 = 0.0;
44107 volatile double dbl2 = 0.0;
44108 duk_computed_nan = dbl1 / dbl2;
44109 } while (0);
44110#endif
44111
44112#if defined(DUK_USE_COMPUTED_INFINITY)
44113 do {
44114 /* Similar workaround for INFINITY. */
44115 volatile double dbl1 = 1.0;
44116 volatile double dbl2 = 0.0;
44117 duk_computed_infinity = dbl1 / dbl2;
44118 } while (0);
44119#endif
44120
44121 /*
44122 * Allocate heap struct
44123 *
44124 * Use a raw call, all macros expect the heap to be initialized
44125 */
44126
44127 res = (duk_heap *) alloc_func(heap_udata, sizeof(duk_heap));
44128 if (!res) {
44129 goto error;
44130 }
44131
44132 /*
44133 * Zero the struct, and start initializing roughly in order
44134 */
44135
44136 DUK_MEMZERO(res, sizeof(*res));
44137
44138 /* explicit NULL inits */
44139#if defined(DUK_USE_EXPLICIT_NULL_INIT)
44140 res->heap_udata = NULL;
44141 res->heap_allocated = NULL;
44142#if defined(DUK_USE_REFERENCE_COUNTING)
44143 res->refzero_list = NULL;
44144 res->refzero_list_tail = NULL;
44145#endif
44146 res->finalize_list = NULL;
44147 res->heap_thread = NULL;
44148 res->curr_thread = NULL;
44149 res->heap_object = NULL;
44150#if defined(DUK_USE_STRTAB_CHAIN)
44151 /* nothing to NULL */
44152#elif defined(DUK_USE_STRTAB_PROBE)
44153#if defined(DUK_USE_HEAPPTR16)
44154 res->strtable16 = (duk_uint16_t *) NULL;
44155#else
44156 res->strtable = (duk_hstring **) NULL;
44157#endif
44158#endif
44159#if defined(DUK_USE_ROM_STRINGS)
44160 /* no res->strs[] */
44161#else /* DUK_USE_ROM_STRINGS */
44162#if defined(DUK_USE_HEAPPTR16)
44163 /* res->strs16[] is zeroed and zero decodes to NULL, so no NULL inits. */
44164#else
44165 {
44166 duk_small_uint_t i;
44167 for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
44168 res->strs[i] = NULL;
44169 }
44170 }
44171#endif
44172#endif /* DUK_USE_ROM_STRINGS */
44173#if defined(DUK_USE_DEBUGGER_SUPPORT)
44174 res->dbg_read_cb = NULL;
44175 res->dbg_write_cb = NULL;
44176 res->dbg_peek_cb = NULL;
44177 res->dbg_read_flush_cb = NULL;
44178 res->dbg_write_flush_cb = NULL;
44179 res->dbg_request_cb = NULL;
44180 res->dbg_udata = NULL;
44181 res->dbg_step_thread = NULL;
44182#endif
44183#endif /* DUK_USE_EXPLICIT_NULL_INIT */
44184
44185 res->alloc_func = alloc_func;
44186 res->realloc_func = realloc_func;
44187 res->free_func = free_func;
44188 res->heap_udata = heap_udata;
44189 res->fatal_func = fatal_func;
44190
44191#if defined(DUK_USE_HEAPPTR16)
44192 /* XXX: zero assumption */
44193 res->heapptr_null16 = DUK_USE_HEAPPTR_ENC16(res->heap_udata, (void *) NULL);
44194 res->heapptr_deleted16 = DUK_USE_HEAPPTR_ENC16(res->heap_udata, (void *) DUK_STRTAB_DELETED_MARKER(res));
44195#endif
44196
44197 /* res->mark_and_sweep_trigger_counter == 0 -> now causes immediate GC; which is OK */
44198
44199 res->call_recursion_depth = 0;
44200 res->call_recursion_limit = DUK_USE_NATIVE_CALL_RECLIMIT;
44201
44202 /* XXX: use the pointer as a seed for now: mix in time at least */
44203
44204 /* The casts through duk_intptr_t is to avoid the following GCC warning:
44205 *
44206 * warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
44207 *
44208 * This still generates a /Wp64 warning on VS2010 when compiling for x86.
44209 */
44210#if defined(DUK_USE_ROM_STRINGS)
44211 /* XXX: make a common DUK_USE_ option, and allow custom fixed seed? */
44212 DUK_D(DUK_DPRINT("using rom strings, force heap hash_seed to fixed value 0x%08lx", (long) DUK__FIXED_HASH_SEED));
44213 res->hash_seed = (duk_uint32_t) DUK__FIXED_HASH_SEED;
44214#else /* DUK_USE_ROM_STRINGS */
44215 res->hash_seed = (duk_uint32_t) (duk_intptr_t) res;
44216#if !defined(DUK_USE_STRHASH_DENSE)
44217 res->hash_seed ^= 5381; /* Bernstein hash init value is normally 5381; XOR it in in case pointer low bits are 0 */
44218#endif
44219#endif /* DUK_USE_ROM_STRINGS */
44220
44221#if defined(DUK_USE_EXPLICIT_NULL_INIT)
44222 res->lj.jmpbuf_ptr = NULL;
44223#endif
44224 DUK_ASSERT(res->lj.type == DUK_LJ_TYPE_UNKNOWN); /* zero */
44225
44226 DUK_TVAL_SET_UNDEFINED(&res->lj.value1);
44227 DUK_TVAL_SET_UNDEFINED(&res->lj.value2);
44228
44229#if (DUK_STRTAB_INITIAL_SIZE < DUK_UTIL_MIN_HASH_PRIME)
44230#error initial heap stringtable size is defined incorrectly
44231#endif
44232
44233 /*
44234 * Init stringtable: fixed variant
44235 */
44236
44237#if defined(DUK_USE_STRTAB_CHAIN)
44238 DUK_MEMZERO(res->strtable, sizeof(duk_strtab_entry) * DUK_STRTAB_CHAIN_SIZE);
44239#if defined(DUK_USE_EXPLICIT_NULL_INIT)
44240 {
44241 duk_small_uint_t i;
44242 for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
44243#if defined(DUK_USE_HEAPPTR16)
44244 res->strtable[i].u.str16 = res->heapptr_null16;
44245#else
44246 res->strtable[i].u.str = NULL;
44247#endif
44248 }
44249 }
44250#endif /* DUK_USE_EXPLICIT_NULL_INIT */
44251#endif /* DUK_USE_STRTAB_CHAIN */
44252
44253 /*
44254 * Init stringtable: probe variant
44255 */
44256
44257#if defined(DUK_USE_STRTAB_PROBE)
44258#if defined(DUK_USE_HEAPPTR16)
44259 res->strtable16 = (duk_uint16_t *) alloc_func(heap_udata, sizeof(duk_uint16_t) * DUK_STRTAB_INITIAL_SIZE);
44260 if (!res->strtable16) {
44261 goto error;
44262 }
44263#else /* DUK_USE_HEAPPTR16 */
44264 res->strtable = (duk_hstring **) alloc_func(heap_udata, sizeof(duk_hstring *) * DUK_STRTAB_INITIAL_SIZE);
44265 if (!res->strtable) {
44266 goto error;
44267 }
44268#endif /* DUK_USE_HEAPPTR16 */
44269 res->st_size = DUK_STRTAB_INITIAL_SIZE;
44270#if defined(DUK_USE_EXPLICIT_NULL_INIT)
44271 {
44272 duk_small_uint_t i;
44273 DUK_ASSERT(res->st_size == DUK_STRTAB_INITIAL_SIZE);
44274 for (i = 0; i < DUK_STRTAB_INITIAL_SIZE; i++) {
44275#if defined(DUK_USE_HEAPPTR16)
44276 res->strtable16[i] = res->heapptr_null16;
44277#else
44278 res->strtable[i] = NULL;
44279#endif
44280 }
44281 }
44282#else /* DUK_USE_EXPLICIT_NULL_INIT */
44283#if defined(DUK_USE_HEAPPTR16)
44284 DUK_MEMZERO(res->strtable16, sizeof(duk_uint16_t) * DUK_STRTAB_INITIAL_SIZE);
44285#else
44286 DUK_MEMZERO(res->strtable, sizeof(duk_hstring *) * DUK_STRTAB_INITIAL_SIZE);
44287#endif
44288#endif /* DUK_USE_EXPLICIT_NULL_INIT */
44289#endif /* DUK_USE_STRTAB_PROBE */
44290
44291 /*
44292 * Init stringcache
44293 */
44294
44295#if defined(DUK_USE_EXPLICIT_NULL_INIT)
44296 {
44297 duk_small_uint_t i;
44298 for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
44299 res->strcache[i].h = NULL;
44300 }
44301 }
44302#endif
44303
44304 /* XXX: error handling is incomplete. It would be cleanest if
44305 * there was a setjmp catchpoint, so that all init code could
44306 * freely throw errors. If that were the case, the return code
44307 * passing here could be removed.
44308 */
44309
44310 /*
44311 * Init built-in strings
44312 */
44313
44314 DUK_DD(DUK_DDPRINT("HEAP: INIT STRINGS"));
44315 if (!duk__init_heap_strings(res)) {
44316 goto error;
44317 }
44318
44319 /*
44320 * Init the heap thread
44321 */
44322
44323 DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP THREAD"));
44324 if (!duk__init_heap_thread(res)) {
44325 goto error;
44326 }
44327
44328 /*
44329 * Init the heap object
44330 */
44331
44332 DUK_DD(DUK_DDPRINT("HEAP: INIT HEAP OBJECT"));
44333 DUK_ASSERT(res->heap_thread != NULL);
44334 res->heap_object = duk_hobject_alloc(res, DUK_HOBJECT_FLAG_EXTENSIBLE |
44335 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT));
44336 if (!res->heap_object) {
44337 goto error;
44338 }
44339 DUK_HOBJECT_INCREF(res->heap_thread, res->heap_object);
44340
44341 /*
44342 * Odds and ends depending on the heap thread
44343 */
44344
44345#if !defined(DUK_USE_GET_RANDOM_DOUBLE)
44346#if defined(DUK_USE_PREFER_SIZE) || !defined(DUK_USE_64BIT_OPS)
44347 res->rnd_state = (duk_uint32_t) DUK_USE_DATE_GET_NOW((duk_context *) res->heap_thread);
44348 duk_util_tinyrandom_prepare_seed(res->heap_thread);
44349#else
44350 res->rnd_state[0] = (duk_uint64_t) DUK_USE_DATE_GET_NOW((duk_context *) res->heap_thread);
44351 DUK_ASSERT(res->rnd_state[1] == 0); /* Not filled here, filled in by seed preparation. */
44352#if 0 /* Manual test values matching misc/xoroshiro128plus_test.c. */
44353 res->rnd_state[0] = 0xdeadbeef12345678ULL;
44354 res->rnd_state[1] = 0xcafed00d12345678ULL;
44355#endif
44356 duk_util_tinyrandom_prepare_seed(res->heap_thread);
44357 /* Mix in heap pointer: this ensures that if two Duktape heaps are
44358 * created on the same millisecond, they get a different PRNG
44359 * sequence (unless e.g. virtual memory addresses cause also the
44360 * heap object pointer to be the same).
44361 */
44362 {
44363 duk_uint64_t tmp_u64;
44364 tmp_u64 = 0;
44365 DUK_MEMCPY((void *) &tmp_u64,
44366 (const void *) &res,
44367 (size_t) (sizeof(void *) >= sizeof(duk_uint64_t) ? sizeof(duk_uint64_t) : sizeof(void *)));
44368 res->rnd_state[1] ^= tmp_u64;
44369 }
44370 do {
44371 duk_small_uint_t i;
44372 for (i = 0; i < 10; i++) {
44373 /* Throw away a few initial random numbers just in
44374 * case. Probably unnecessary due to SplitMix64
44375 * preparation.
44376 */
44377 (void) duk_util_tinyrandom_get_double(res->heap_thread);
44378 }
44379 } while (0);
44380#endif
44381#endif
44382
44383 /*
44384 * All done
44385 */
44386
44387 DUK_D(DUK_DPRINT("allocated heap: %p", (void *) res));
44388 return res;
44389
44390 error:
44391 DUK_D(DUK_DPRINT("heap allocation failed"));
44392
44393 if (res) {
44394 /* assumes that allocated pointers and alloc funcs are valid
44395 * if res exists
44396 */
44397 DUK_ASSERT(res->alloc_func != NULL);
44398 DUK_ASSERT(res->realloc_func != NULL);
44399 DUK_ASSERT(res->free_func != NULL);
44400 duk_heap_free(res);
44401 }
44402 return NULL;
44403}
44404
44405/* automatic undefs */
44406#undef DUK__DUMPLM_SIGNED
44407#undef DUK__DUMPLM_SIGNED_RAW
44408#undef DUK__DUMPLM_UNSIGNED
44409#undef DUK__DUMPLM_UNSIGNED_RAW
44410#undef DUK__DUMPSZ
44411#undef DUK__FIXED_HASH_SEED
44412/*
44413 * String hash computation (interning).
44414 *
44415 * String hashing is performance critical because a string hash is computed
44416 * for all new strings which are candidates to be added to the string table.
44417 * However, strings actually added to the string table go through a codepoint
44418 * length calculation which dominates performance because it goes through
44419 * every byte of the input string (but only for strings added).
44420 *
44421 * The string hash algorithm should be fast, but on the other hand provide
44422 * good enough hashes to ensure both string table and object property table
44423 * hash tables work reasonably well (i.e., there aren't too many collisions
44424 * with real world inputs). Unless the hash is cryptographic, it's always
44425 * possible to craft inputs with maximal hash collisions.
44426 *
44427 * NOTE: The hash algorithms must match tools/dukutil.py:duk_heap_hashstring()
44428 * for ROM string support!
44429 */
44430
44431/* #include duk_internal.h -> already included */
44432
44433#if defined(DUK_USE_STRHASH_DENSE)
44434/* Constants for duk_hashstring(). */
44435#define DUK__STRHASH_SHORTSTRING 4096L
44436#define DUK__STRHASH_MEDIUMSTRING (256L * 1024L)
44437#define DUK__STRHASH_BLOCKSIZE 256L
44438
44439DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len) {
44440 duk_uint32_t hash;
44441
44442 /* Use Murmurhash2 directly for short strings, and use "block skipping"
44443 * for long strings: hash an initial part and then sample the rest of
44444 * the string with reasonably sized chunks. An initial offset for the
44445 * sampling is computed based on a hash of the initial part of the string;
44446 * this is done to (usually) avoid the case where all long strings have
44447 * certain offset ranges which are never sampled.
44448 *
44449 * Skip should depend on length and bound the total time to roughly
44450 * logarithmic. With current values:
44451 *
44452 * 1M string => 256 * 241 = 61696 bytes (0.06M) of hashing
44453 * 1G string => 256 * 16321 = 4178176 bytes (3.98M) of hashing
44454 *
44455 * XXX: It would be better to compute the skip offset more "smoothly"
44456 * instead of having a few boundary values.
44457 */
44458
44459 /* note: mixing len into seed improves hashing when skipping */
44460 duk_uint32_t str_seed = heap->hash_seed ^ ((duk_uint32_t) len);
44461
44462 if (len <= DUK__STRHASH_SHORTSTRING) {
44463 hash = duk_util_hashbytes(str, len, str_seed);
44464 } else {
44465 duk_size_t off;
44466 duk_size_t skip;
44467
44468 if (len <= DUK__STRHASH_MEDIUMSTRING) {
44469 skip = (duk_size_t) (16 * DUK__STRHASH_BLOCKSIZE + DUK__STRHASH_BLOCKSIZE);
44470 } else {
44471 skip = (duk_size_t) (256 * DUK__STRHASH_BLOCKSIZE + DUK__STRHASH_BLOCKSIZE);
44472 }
44473
44474 hash = duk_util_hashbytes(str, (duk_size_t) DUK__STRHASH_SHORTSTRING, str_seed);
44475 off = DUK__STRHASH_SHORTSTRING + (skip * (hash % 256)) / 256;
44476
44477 /* XXX: inefficient loop */
44478 while (off < len) {
44479 duk_size_t left = len - off;
44480 duk_size_t now = (duk_size_t) (left > DUK__STRHASH_BLOCKSIZE ? DUK__STRHASH_BLOCKSIZE : left);
44481 hash ^= duk_util_hashbytes(str + off, now, str_seed);
44482 off += skip;
44483 }
44484 }
44485
44486#if defined(DUK_USE_STRHASH16)
44487 /* Truncate to 16 bits here, so that a computed hash can be compared
44488 * against a hash stored in a 16-bit field.
44489 */
44490 hash &= 0x0000ffffUL;
44491#endif
44492 return hash;
44493}
44494#else /* DUK_USE_STRHASH_DENSE */
44495DUK_INTERNAL duk_uint32_t duk_heap_hashstring(duk_heap *heap, const duk_uint8_t *str, duk_size_t len) {
44496 duk_uint32_t hash;
44497 duk_size_t step;
44498 duk_size_t off;
44499
44500 /* Slightly modified "Bernstein hash" from:
44501 *
44502 * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx
44503 *
44504 * Modifications: string skipping and reverse direction similar to
44505 * Lua 5.1.5, and different hash initializer.
44506 *
44507 * The reverse direction ensures last byte it always included in the
44508 * hash which is a good default as changing parts of the string are
44509 * more often in the suffix than in the prefix.
44510 */
44511
44512 hash = heap->hash_seed ^ ((duk_uint32_t) len); /* Bernstein hash init value is normally 5381 */
44513 step = (len >> DUK_USE_STRHASH_SKIP_SHIFT) + 1;
44514 for (off = len; off >= step; off -= step) {
44515 DUK_ASSERT(off >= 1); /* off >= step, and step >= 1 */
44516 hash = (hash * 33) + str[off - 1];
44517 }
44518
44519#if defined(DUK_USE_STRHASH16)
44520 /* Truncate to 16 bits here, so that a computed hash can be compared
44521 * against a hash stored in a 16-bit field.
44522 */
44523 hash &= 0x0000ffffUL;
44524#endif
44525 return hash;
44526}
44527#endif /* DUK_USE_STRHASH_DENSE */
44528
44529/* automatic undefs */
44530#undef DUK__STRHASH_BLOCKSIZE
44531#undef DUK__STRHASH_MEDIUMSTRING
44532#undef DUK__STRHASH_SHORTSTRING
44533/*
44534 * Mark-and-sweep garbage collection.
44535 */
44536
44537/* #include duk_internal.h -> already included */
44538
44539DUK_LOCAL_DECL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h);
44540DUK_LOCAL_DECL void duk__mark_tval(duk_heap *heap, duk_tval *tv);
44541
44542/*
44543 * Misc
44544 */
44545
44546/* Select a thread for mark-and-sweep use.
44547 *
44548 * XXX: This needs to change later.
44549 */
44550DUK_LOCAL duk_hthread *duk__get_temp_hthread(duk_heap *heap) {
44551 if (heap->curr_thread) {
44552 return heap->curr_thread;
44553 }
44554 return heap->heap_thread; /* may be NULL, too */
44555}
44556
44557/*
44558 * Marking functions for heap types: mark children recursively
44559 */
44560
44561DUK_LOCAL void duk__mark_hstring(duk_heap *heap, duk_hstring *h) {
44562 DUK_UNREF(heap);
44563 DUK_UNREF(h);
44564
44565 DUK_DDD(DUK_DDDPRINT("duk__mark_hstring: %p", (void *) h));
44566 DUK_ASSERT(h);
44567
44568 /* nothing to process */
44569}
44570
44571DUK_LOCAL void duk__mark_hobject(duk_heap *heap, duk_hobject *h) {
44572 duk_uint_fast32_t i;
44573
44574 DUK_DDD(DUK_DDDPRINT("duk__mark_hobject: %p", (void *) h));
44575
44576 DUK_ASSERT(h);
44577
44578 /* XXX: use advancing pointers instead of index macros -> faster and smaller? */
44579
44580 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(h); i++) {
44581 duk_hstring *key = DUK_HOBJECT_E_GET_KEY(heap, h, i);
44582 if (!key) {
44583 continue;
44584 }
44585 duk__mark_heaphdr(heap, (duk_heaphdr *) key);
44586 if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, h, i)) {
44587 duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.get);
44588 duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->a.set);
44589 } else {
44590 duk__mark_tval(heap, &DUK_HOBJECT_E_GET_VALUE_PTR(heap, h, i)->v);
44591 }
44592 }
44593
44594 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(h); i++) {
44595 duk__mark_tval(heap, DUK_HOBJECT_A_GET_VALUE_PTR(heap, h, i));
44596 }
44597
44598 /* hash part is a 'weak reference' and does not contribute */
44599
44600 duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HOBJECT_GET_PROTOTYPE(heap, h));
44601
44602 /* XXX: rearrange bits to allow a switch case to be used here? */
44603 /* XXX: add a fast path for objects (and arrays)? */
44604 /* DUK_HOBJECT_IS_ARRAY(h): needs no special handling now as there are
44605 * no extra fields in need of marking.
44606 */
44607 if (DUK_HOBJECT_IS_COMPFUNC(h)) {
44608 duk_hcompfunc *f = (duk_hcompfunc *) h;
44609 duk_tval *tv, *tv_end;
44610 duk_hobject **fn, **fn_end;
44611
44612 /* 'data' is reachable through every compiled function which
44613 * contains a reference.
44614 */
44615
44616 duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HCOMPFUNC_GET_DATA(heap, f));
44617 duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HCOMPFUNC_GET_LEXENV(heap, f));
44618 duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_HCOMPFUNC_GET_VARENV(heap, f));
44619
44620 if (DUK_HCOMPFUNC_GET_DATA(heap, f) != NULL) {
44621 tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(heap, f);
44622 tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(heap, f);
44623 while (tv < tv_end) {
44624 duk__mark_tval(heap, tv);
44625 tv++;
44626 }
44627
44628 fn = DUK_HCOMPFUNC_GET_FUNCS_BASE(heap, f);
44629 fn_end = DUK_HCOMPFUNC_GET_FUNCS_END(heap, f);
44630 while (fn < fn_end) {
44631 duk__mark_heaphdr(heap, (duk_heaphdr *) *fn);
44632 fn++;
44633 }
44634 } else {
44635 /* May happen in some out-of-memory corner cases. */
44636 DUK_D(DUK_DPRINT("duk_hcompfunc 'data' is NULL, skipping marking"));
44637 }
44638 } else if (DUK_HOBJECT_IS_NATFUNC(h)) {
44639 duk_hnatfunc *f = (duk_hnatfunc *) h;
44640 DUK_UNREF(f);
44641 /* nothing to mark */
44642#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
44643 } else if (DUK_HOBJECT_IS_BUFOBJ(h)) {
44644 duk_hbufobj *b = (duk_hbufobj *) h;
44645 duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf);
44646 duk__mark_heaphdr(heap, (duk_heaphdr *) b->buf_prop);
44647#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
44648 } else if (DUK_HOBJECT_IS_THREAD(h)) {
44649 duk_hthread *t = (duk_hthread *) h;
44650 duk_tval *tv;
44651
44652 tv = t->valstack;
44653 while (tv < t->valstack_top) {
44654 duk__mark_tval(heap, tv);
44655 tv++;
44656 }
44657
44658 for (i = 0; i < (duk_uint_fast32_t) t->callstack_top; i++) {
44659 duk_activation *act = t->callstack + i;
44660 duk__mark_heaphdr(heap, (duk_heaphdr *) DUK_ACT_GET_FUNC(act));
44661 duk__mark_heaphdr(heap, (duk_heaphdr *) act->var_env);
44662 duk__mark_heaphdr(heap, (duk_heaphdr *) act->lex_env);
44663#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
44664 duk__mark_heaphdr(heap, (duk_heaphdr *) act->prev_caller);
44665#endif
44666 }
44667
44668#if 0 /* nothing now */
44669 for (i = 0; i < (duk_uint_fast32_t) t->catchstack_top; i++) {
44670 duk_catcher *cat = t->catchstack + i;
44671 }
44672#endif
44673
44674 duk__mark_heaphdr(heap, (duk_heaphdr *) t->resumer);
44675
44676 /* XXX: duk_small_uint_t would be enough for this loop */
44677 for (i = 0; i < DUK_NUM_BUILTINS; i++) {
44678 duk__mark_heaphdr(heap, (duk_heaphdr *) t->builtins[i]);
44679 }
44680 }
44681}
44682
44683/* recursion tracking happens here only */
44684DUK_LOCAL void duk__mark_heaphdr(duk_heap *heap, duk_heaphdr *h) {
44685 DUK_DDD(DUK_DDDPRINT("duk__mark_heaphdr %p, type %ld",
44686 (void *) h,
44687 (h != NULL ? (long) DUK_HEAPHDR_GET_TYPE(h) : (long) -1)));
44688 if (!h) {
44689 return;
44690 }
44691#if defined(DUK_USE_ROM_OBJECTS)
44692 if (DUK_HEAPHDR_HAS_READONLY(h)) {
44693 DUK_DDD(DUK_DDDPRINT("readonly object %p, skip", (void *) h));
44694 return;
44695 }
44696#endif
44697 if (DUK_HEAPHDR_HAS_REACHABLE(h)) {
44698 DUK_DDD(DUK_DDDPRINT("already marked reachable, skip"));
44699 return;
44700 }
44701 DUK_HEAPHDR_SET_REACHABLE(h);
44702
44703 if (heap->mark_and_sweep_recursion_depth >= DUK_USE_MARK_AND_SWEEP_RECLIMIT) {
44704 /* log this with a normal debug level because this should be relatively rare */
44705 DUK_D(DUK_DPRINT("mark-and-sweep recursion limit reached, marking as temproot: %p", (void *) h));
44706 DUK_HEAP_SET_MARKANDSWEEP_RECLIMIT_REACHED(heap);
44707 DUK_HEAPHDR_SET_TEMPROOT(h);
44708 return;
44709 }
44710
44711 heap->mark_and_sweep_recursion_depth++;
44712
44713 switch (DUK_HEAPHDR_GET_TYPE(h)) {
44714 case DUK_HTYPE_STRING:
44715 duk__mark_hstring(heap, (duk_hstring *) h);
44716 break;
44717 case DUK_HTYPE_OBJECT:
44718 duk__mark_hobject(heap, (duk_hobject *) h);
44719 break;
44720 case DUK_HTYPE_BUFFER:
44721 /* nothing to mark */
44722 break;
44723 default:
44724 DUK_D(DUK_DPRINT("attempt to mark heaphdr %p with invalid htype %ld", (void *) h, (long) DUK_HEAPHDR_GET_TYPE(h)));
44725 DUK_UNREACHABLE();
44726 }
44727
44728 heap->mark_and_sweep_recursion_depth--;
44729}
44730
44731DUK_LOCAL void duk__mark_tval(duk_heap *heap, duk_tval *tv) {
44732 DUK_DDD(DUK_DDDPRINT("duk__mark_tval %p", (void *) tv));
44733 if (!tv) {
44734 return;
44735 }
44736 if (DUK_TVAL_IS_HEAP_ALLOCATED(tv)) {
44737 duk__mark_heaphdr(heap, DUK_TVAL_GET_HEAPHDR(tv));
44738 }
44739}
44740
44741/*
44742 * Mark the heap.
44743 */
44744
44745DUK_LOCAL void duk__mark_roots_heap(duk_heap *heap) {
44746 duk_small_uint_t i;
44747
44748 DUK_DD(DUK_DDPRINT("duk__mark_roots_heap: %p", (void *) heap));
44749
44750 duk__mark_heaphdr(heap, (duk_heaphdr *) heap->heap_thread);
44751 duk__mark_heaphdr(heap, (duk_heaphdr *) heap->heap_object);
44752
44753 for (i = 0; i < DUK_HEAP_NUM_STRINGS; i++) {
44754 duk_hstring *h = DUK_HEAP_GET_STRING(heap, i);
44755 duk__mark_heaphdr(heap, (duk_heaphdr *) h);
44756 }
44757
44758 duk__mark_tval(heap, &heap->lj.value1);
44759 duk__mark_tval(heap, &heap->lj.value2);
44760
44761#if defined(DUK_USE_DEBUGGER_SUPPORT)
44762 for (i = 0; i < heap->dbg_breakpoint_count; i++) {
44763 duk__mark_heaphdr(heap, (duk_heaphdr *) heap->dbg_breakpoints[i].filename);
44764 }
44765#endif
44766}
44767
44768/*
44769 * Mark refzero_list objects.
44770 *
44771 * Objects on the refzero_list have no inbound references. They might have
44772 * outbound references to objects that we might free, which would invalidate
44773 * any references held by the refzero objects. A refzero object might also
44774 * be rescued by refcount finalization. Refzero objects are treated as
44775 * reachability roots to ensure they (or anything they point to) are not
44776 * freed in mark-and-sweep.
44777 */
44778
44779#if defined(DUK_USE_REFERENCE_COUNTING)
44780DUK_LOCAL void duk__mark_refzero_list(duk_heap *heap) {
44781 duk_heaphdr *hdr;
44782
44783 DUK_DD(DUK_DDPRINT("duk__mark_refzero_list: %p", (void *) heap));
44784
44785 hdr = heap->refzero_list;
44786 while (hdr) {
44787 duk__mark_heaphdr(heap, hdr);
44788 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
44789 }
44790}
44791#endif
44792
44793/*
44794 * Mark unreachable, finalizable objects.
44795 *
44796 * Such objects will be moved aside and their finalizers run later. They have
44797 * to be treated as reachability roots for their properties etc to remain
44798 * allocated. This marking is only done for unreachable values which would
44799 * be swept later (refzero_list is thus excluded).
44800 *
44801 * Objects are first marked FINALIZABLE and only then marked as reachability
44802 * roots; otherwise circular references might be handled inconsistently.
44803 */
44804
44805#if defined(DUK_USE_FINALIZER_SUPPORT)
44806DUK_LOCAL void duk__mark_finalizable(duk_heap *heap) {
44807 duk_hthread *thr;
44808 duk_heaphdr *hdr;
44809 duk_size_t count_finalizable = 0;
44810
44811 DUK_DD(DUK_DDPRINT("duk__mark_finalizable: %p", (void *) heap));
44812
44813 thr = duk__get_temp_hthread(heap);
44814 DUK_ASSERT(thr != NULL);
44815
44816 hdr = heap->heap_allocated;
44817 while (hdr) {
44818 /* A finalizer is looked up from the object and up its prototype chain
44819 * (which allows inherited finalizers). A prototype loop must not cause
44820 * an error to be thrown here; duk_hobject_hasprop_raw() will ignore a
44821 * prototype loop silently and indicate that the property doesn't exist.
44822 */
44823
44824 if (!DUK_HEAPHDR_HAS_REACHABLE(hdr) &&
44825 DUK_HEAPHDR_GET_TYPE(hdr) == DUK_HTYPE_OBJECT &&
44826 !DUK_HEAPHDR_HAS_FINALIZED(hdr) &&
44827 duk_hobject_hasprop_raw(thr, (duk_hobject *) hdr, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) {
44828
44829 /* heaphdr:
44830 * - is not reachable
44831 * - is an object
44832 * - is not a finalized object
44833 * - has a finalizer
44834 */
44835
44836 DUK_DD(DUK_DDPRINT("unreachable heap object will be "
44837 "finalized -> mark as finalizable "
44838 "and treat as a reachability root: %p",
44839 (void *) hdr));
44840 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(hdr));
44841 DUK_HEAPHDR_SET_FINALIZABLE(hdr);
44842 count_finalizable ++;
44843 }
44844
44845 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
44846 }
44847
44848 if (count_finalizable == 0) {
44849 return;
44850 }
44851
44852 DUK_DD(DUK_DDPRINT("marked %ld heap objects as finalizable, now mark them reachable",
44853 (long) count_finalizable));
44854
44855 hdr = heap->heap_allocated;
44856 while (hdr) {
44857 if (DUK_HEAPHDR_HAS_FINALIZABLE(hdr)) {
44858 duk__mark_heaphdr(heap, hdr);
44859 }
44860
44861 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
44862 }
44863
44864 /* Caller will finish the marking process if we hit a recursion limit. */
44865}
44866#endif /* DUK_USE_FINALIZER_SUPPORT */
44867
44868/*
44869 * Mark objects on finalize_list.
44870 *
44871 */
44872
44873#if defined(DUK_USE_FINALIZER_SUPPORT)
44874DUK_LOCAL void duk__mark_finalize_list(duk_heap *heap) {
44875 duk_heaphdr *hdr;
44876#if defined(DUK_USE_DEBUG)
44877 duk_size_t count_finalize_list = 0;
44878#endif
44879
44880 DUK_DD(DUK_DDPRINT("duk__mark_finalize_list: %p", (void *) heap));
44881
44882 hdr = heap->finalize_list;
44883 while (hdr) {
44884 duk__mark_heaphdr(heap, hdr);
44885 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
44886#if defined(DUK_USE_DEBUG)
44887 count_finalize_list++;
44888#endif
44889 }
44890
44891#if defined(DUK_USE_DEBUG)
44892 if (count_finalize_list > 0) {
44893 DUK_D(DUK_DPRINT("marked %ld objects on the finalize_list as reachable (previous finalizer run skipped)",
44894 (long) count_finalize_list));
44895 }
44896#endif
44897}
44898#endif /* DUK_USE_FINALIZER_SUPPORT */
44899
44900/*
44901 * Fallback marking handler if recursion limit is reached.
44902 *
44903 * Iterates 'temproots' until recursion limit is no longer hit. Note
44904 * that temproots may reside either in heap allocated list or the
44905 * refzero work list. This is a slow scan, but guarantees that we
44906 * finish with a bounded C stack.
44907 *
44908 * Note that nodes may have been marked as temproots before this
44909 * scan begun, OR they may have been marked during the scan (as
44910 * we process nodes recursively also during the scan). This is
44911 * intended behavior.
44912 */
44913
44914#if defined(DUK_USE_DEBUG)
44915DUK_LOCAL void duk__handle_temproot(duk_heap *heap, duk_heaphdr *hdr, duk_size_t *count) {
44916#else
44917DUK_LOCAL void duk__handle_temproot(duk_heap *heap, duk_heaphdr *hdr) {
44918#endif
44919 if (!DUK_HEAPHDR_HAS_TEMPROOT(hdr)) {
44920 DUK_DDD(DUK_DDDPRINT("not a temp root: %p", (void *) hdr));
44921 return;
44922 }
44923
44924 DUK_DDD(DUK_DDDPRINT("found a temp root: %p", (void *) hdr));
44925 DUK_HEAPHDR_CLEAR_TEMPROOT(hdr);
44926 DUK_HEAPHDR_CLEAR_REACHABLE(hdr); /* done so that duk__mark_heaphdr() works correctly */
44927 duk__mark_heaphdr(heap, hdr);
44928
44929#if defined(DUK_USE_DEBUG)
44930 (*count)++;
44931#endif
44932}
44933
44934DUK_LOCAL void duk__mark_temproots_by_heap_scan(duk_heap *heap) {
44935 duk_heaphdr *hdr;
44936#if defined(DUK_USE_DEBUG)
44937 duk_size_t count;
44938#endif
44939
44940 DUK_DD(DUK_DDPRINT("duk__mark_temproots_by_heap_scan: %p", (void *) heap));
44941
44942 while (DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap)) {
44943 DUK_DD(DUK_DDPRINT("recursion limit reached, doing heap scan to continue from temproots"));
44944
44945#if defined(DUK_USE_DEBUG)
44946 count = 0;
44947#endif
44948 DUK_HEAP_CLEAR_MARKANDSWEEP_RECLIMIT_REACHED(heap);
44949
44950 hdr = heap->heap_allocated;
44951 while (hdr) {
44952#if defined(DUK_USE_DEBUG)
44953 duk__handle_temproot(heap, hdr, &count);
44954#else
44955 duk__handle_temproot(heap, hdr);
44956#endif
44957 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
44958 }
44959
44960 /* must also check refzero_list */
44961#if defined(DUK_USE_REFERENCE_COUNTING)
44962 hdr = heap->refzero_list;
44963 while (hdr) {
44964#if defined(DUK_USE_DEBUG)
44965 duk__handle_temproot(heap, hdr, &count);
44966#else
44967 duk__handle_temproot(heap, hdr);
44968#endif
44969 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
44970 }
44971#endif /* DUK_USE_REFERENCE_COUNTING */
44972
44973#if defined(DUK_USE_DEBUG)
44974 DUK_DD(DUK_DDPRINT("temproot mark heap scan processed %ld temp roots", (long) count));
44975#endif
44976 }
44977}
44978
44979/*
44980 * Finalize refcounts for heap elements just about to be freed.
44981 * This must be done for all objects before freeing to avoid any
44982 * stale pointer dereferences.
44983 *
44984 * Note that this must deduce the set of objects to be freed
44985 * identically to duk__sweep_heap().
44986 */
44987
44988#if defined(DUK_USE_REFERENCE_COUNTING)
44989DUK_LOCAL void duk__finalize_refcounts(duk_heap *heap) {
44990 duk_hthread *thr;
44991 duk_heaphdr *hdr;
44992
44993 thr = duk__get_temp_hthread(heap);
44994 DUK_ASSERT(thr != NULL);
44995
44996 DUK_DD(DUK_DDPRINT("duk__finalize_refcounts: heap=%p, hthread=%p",
44997 (void *) heap, (void *) thr));
44998
44999 hdr = heap->heap_allocated;
45000 while (hdr) {
45001 if (!DUK_HEAPHDR_HAS_REACHABLE(hdr)) {
45002 /*
45003 * Unreachable object about to be swept. Finalize target refcounts
45004 * (objects which the unreachable object points to) without doing
45005 * refzero processing. Recursive decrefs are also prevented when
45006 * refzero processing is disabled.
45007 *
45008 * Value cannot be a finalizable object, as they have been made
45009 * temporarily reachable for this round.
45010 */
45011
45012 DUK_DDD(DUK_DDDPRINT("unreachable object, refcount finalize before sweeping: %p", (void *) hdr));
45013 duk_heaphdr_refcount_finalize(thr, hdr);
45014 }
45015
45016 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
45017 }
45018}
45019#endif /* DUK_USE_REFERENCE_COUNTING */
45020
45021/*
45022 * Clear (reachable) flags of refzero work list.
45023 */
45024
45025#if defined(DUK_USE_REFERENCE_COUNTING)
45026DUK_LOCAL void duk__clear_refzero_list_flags(duk_heap *heap) {
45027 duk_heaphdr *hdr;
45028
45029 DUK_DD(DUK_DDPRINT("duk__clear_refzero_list_flags: %p", (void *) heap));
45030
45031 hdr = heap->refzero_list;
45032 while (hdr) {
45033 DUK_HEAPHDR_CLEAR_REACHABLE(hdr);
45034 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr));
45035 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr));
45036 DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr));
45037 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
45038 }
45039}
45040#endif /* DUK_USE_REFERENCE_COUNTING */
45041
45042/*
45043 * Clear (reachable) flags of finalize_list
45044 *
45045 * We could mostly do in the sweep phase when we move objects from the
45046 * heap into the finalize_list. However, if a finalizer run is skipped
45047 * during a mark-and-sweep, the objects on the finalize_list will be marked
45048 * reachable during the next mark-and-sweep. Since they're already on the
45049 * finalize_list, no-one will be clearing their REACHABLE flag so we do it
45050 * here. (This now overlaps with the sweep handling in a harmless way.)
45051 */
45052
45053#if defined(DUK_USE_FINALIZER_SUPPORT)
45054DUK_LOCAL void duk__clear_finalize_list_flags(duk_heap *heap) {
45055 duk_heaphdr *hdr;
45056
45057 DUK_DD(DUK_DDPRINT("duk__clear_finalize_list_flags: %p", (void *) heap));
45058
45059 hdr = heap->finalize_list;
45060 while (hdr) {
45061 DUK_HEAPHDR_CLEAR_REACHABLE(hdr);
45062 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr));
45063 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr));
45064 DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr));
45065 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
45066 }
45067}
45068#endif /* DUK_USE_FINALIZER_SUPPORT */
45069
45070/*
45071 * Sweep stringtable
45072 */
45073
45074#if defined(DUK_USE_STRTAB_CHAIN)
45075
45076/* XXX: skip count_free w/o debug? */
45077#if defined(DUK_USE_HEAPPTR16)
45078DUK_LOCAL void duk__sweep_string_chain16(duk_heap *heap, duk_uint16_t *slot, duk_size_t *count_keep, duk_size_t *count_free) {
45079 duk_uint16_t h16 = *slot;
45080 duk_hstring *h;
45081 duk_uint16_t null16 = heap->heapptr_null16;
45082
45083 if (h16 == null16) {
45084 /* nop */
45085 return;
45086 }
45087 h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, h16);
45088 DUK_ASSERT(h != NULL);
45089
45090 if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) {
45091 DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h);
45092 (*count_keep)++;
45093 } else {
45094#if defined(DUK_USE_REFERENCE_COUNTING)
45095 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0);
45096#endif
45097 /* deal with weak references first */
45098 duk_heap_strcache_string_remove(heap, (duk_hstring *) h);
45099 *slot = null16;
45100
45101 /* free inner references (these exist e.g. when external
45102 * strings are enabled)
45103 */
45104 duk_free_hstring(heap, h);
45105 (*count_free)++;
45106 }
45107}
45108#else /* DUK_USE_HEAPPTR16 */
45109DUK_LOCAL void duk__sweep_string_chain(duk_heap *heap, duk_hstring **slot, duk_size_t *count_keep, duk_size_t *count_free) {
45110 duk_hstring *h = *slot;
45111
45112 if (h == NULL) {
45113 /* nop */
45114 return;
45115 }
45116
45117 if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) {
45118 DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h);
45119 (*count_keep)++;
45120 } else {
45121#if defined(DUK_USE_REFERENCE_COUNTING)
45122 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0);
45123#endif
45124 /* deal with weak references first */
45125 duk_heap_strcache_string_remove(heap, (duk_hstring *) h);
45126 *slot = NULL;
45127
45128 /* free inner references (these exist e.g. when external
45129 * strings are enabled)
45130 */
45131 duk_free_hstring(heap, h);
45132 (*count_free)++;
45133 }
45134}
45135#endif /* DUK_USE_HEAPPTR16 */
45136
45137DUK_LOCAL void duk__sweep_stringtable_chain(duk_heap *heap, duk_size_t *out_count_keep) {
45139 duk_uint_fast32_t i;
45140 duk_size_t count_free = 0;
45141 duk_size_t count_keep = 0;
45142 duk_size_t j, n;
45143#if defined(DUK_USE_HEAPPTR16)
45144 duk_uint16_t *lst;
45145#else
45146 duk_hstring **lst;
45147#endif
45148
45149 DUK_DD(DUK_DDPRINT("duk__sweep_stringtable: %p", (void *) heap));
45150
45151 /* Non-zero refcounts should not happen for unreachable strings,
45152 * because we refcount finalize all unreachable objects which
45153 * should have decreased unreachable string refcounts to zero
45154 * (even for cycles).
45155 */
45156
45157 for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
45158 e = heap->strtable + i;
45159 if (e->listlen == 0) {
45160#if defined(DUK_USE_HEAPPTR16)
45161 duk__sweep_string_chain16(heap, &e->u.str16, &count_keep, &count_free);
45162#else
45163 duk__sweep_string_chain(heap, &e->u.str, &count_keep, &count_free);
45164#endif
45165 } else {
45166#if defined(DUK_USE_HEAPPTR16)
45167 lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
45168#else
45169 lst = e->u.strlist;
45170#endif
45171 for (j = 0, n = e->listlen; j < n; j++) {
45172#if defined(DUK_USE_HEAPPTR16)
45173 duk__sweep_string_chain16(heap, lst + j, &count_keep, &count_free);
45174#else
45175 duk__sweep_string_chain(heap, lst + j, &count_keep, &count_free);
45176#endif
45177 }
45178 }
45179 }
45180
45181 DUK_D(DUK_DPRINT("mark-and-sweep sweep stringtable: %ld freed, %ld kept",
45182 (long) count_free, (long) count_keep));
45183 *out_count_keep = count_keep;
45184}
45185#endif /* DUK_USE_STRTAB_CHAIN */
45186
45187#if defined(DUK_USE_STRTAB_PROBE)
45188DUK_LOCAL void duk__sweep_stringtable_probe(duk_heap *heap, duk_size_t *out_count_keep) {
45189 duk_hstring *h;
45190 duk_uint_fast32_t i;
45191#if defined(DUK_USE_DEBUG)
45192 duk_size_t count_free = 0;
45193#endif
45194 duk_size_t count_keep = 0;
45195
45196 DUK_DD(DUK_DDPRINT("duk__sweep_stringtable: %p", (void *) heap));
45197
45198 for (i = 0; i < heap->st_size; i++) {
45199#if defined(DUK_USE_HEAPPTR16)
45200 h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]);
45201#else
45202 h = heap->strtable[i];
45203#endif
45204 if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) {
45205 continue;
45206 } else if (DUK_HEAPHDR_HAS_REACHABLE((duk_heaphdr *) h)) {
45207 DUK_HEAPHDR_CLEAR_REACHABLE((duk_heaphdr *) h);
45208 count_keep++;
45209 continue;
45210 }
45211
45212#if defined(DUK_USE_DEBUG)
45213 count_free++;
45214#endif
45215
45216#if defined(DUK_USE_REFERENCE_COUNTING)
45217 /* Non-zero refcounts should not happen for unreachable strings,
45218 * because we refcount finalize all unreachable objects which
45219 * should have decreased unreachable string refcounts to zero
45220 * (even for cycles).
45221 */
45222 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) == 0);
45223#endif
45224
45225 DUK_DDD(DUK_DDDPRINT("sweep string, not reachable: %p", (void *) h));
45226
45227 /* deal with weak references first */
45228 duk_heap_strcache_string_remove(heap, (duk_hstring *) h);
45229
45230 /* remove the string (mark DELETED), could also call
45231 * duk_heap_string_remove() but that would be slow and
45232 * pointless because we already know the slot.
45233 */
45234#if defined(DUK_USE_HEAPPTR16)
45235 heap->strtable16[i] = heap->heapptr_deleted16;
45236#else
45237 heap->strtable[i] = DUK_STRTAB_DELETED_MARKER(heap);
45238#endif
45239
45240 /* free inner references (these exist e.g. when external
45241 * strings are enabled) and the struct itself.
45242 */
45243 duk_free_hstring(heap, (duk_hstring *) h);
45244 }
45245
45246#if defined(DUK_USE_DEBUG)
45247 DUK_D(DUK_DPRINT("mark-and-sweep sweep stringtable: %ld freed, %ld kept",
45248 (long) count_free, (long) count_keep));
45249#endif
45250 *out_count_keep = count_keep;
45251}
45252#endif /* DUK_USE_STRTAB_PROBE */
45253
45254/*
45255 * Sweep heap
45256 */
45257
45258DUK_LOCAL void duk__sweep_heap(duk_heap *heap, duk_int_t flags, duk_size_t *out_count_keep) {
45259 duk_heaphdr *prev; /* last element that was left in the heap */
45260 duk_heaphdr *curr;
45261 duk_heaphdr *next;
45262#if defined(DUK_USE_DEBUG)
45263 duk_size_t count_free = 0;
45264 duk_size_t count_finalize = 0;
45265 duk_size_t count_rescue = 0;
45266#endif
45267 duk_size_t count_keep = 0;
45268
45269 DUK_UNREF(flags);
45270 DUK_DD(DUK_DDPRINT("duk__sweep_heap: %p", (void *) heap));
45271
45272 prev = NULL;
45273 curr = heap->heap_allocated;
45274 heap->heap_allocated = NULL;
45275 while (curr) {
45276 /* Strings and ROM objects are never placed on the heap allocated list. */
45277 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) != DUK_HTYPE_STRING);
45278 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(curr));
45279
45280 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
45281
45282 if (DUK_HEAPHDR_HAS_REACHABLE(curr)) {
45283 /*
45284 * Reachable object, keep
45285 */
45286
45287 DUK_DDD(DUK_DDDPRINT("sweep, reachable: %p", (void *) curr));
45288
45289 if (DUK_HEAPHDR_HAS_FINALIZABLE(curr)) {
45290 /*
45291 * If object has been marked finalizable, move it to the
45292 * "to be finalized" work list. It will be collected on
45293 * the next mark-and-sweep if it is still unreachable
45294 * after running the finalizer.
45295 */
45296
45297 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
45298 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT);
45299 DUK_DDD(DUK_DDDPRINT("object has finalizer, move to finalization work list: %p", (void *) curr));
45300
45301#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
45302 if (heap->finalize_list) {
45303 DUK_HEAPHDR_SET_PREV(heap, heap->finalize_list, curr);
45304 }
45305 DUK_HEAPHDR_SET_PREV(heap, curr, NULL);
45306#endif
45307 DUK_HEAPHDR_SET_NEXT(heap, curr, heap->finalize_list);
45308 DUK_ASSERT_HEAPHDR_LINKS(heap, curr);
45309 heap->finalize_list = curr;
45310#if defined(DUK_USE_DEBUG)
45311 count_finalize++;
45312#endif
45313 } else {
45314 /*
45315 * Object will be kept; queue object back to heap_allocated (to tail)
45316 */
45317
45318 if (DUK_HEAPHDR_HAS_FINALIZED(curr)) {
45319 /*
45320 * Object's finalizer was executed on last round, and
45321 * object has been happily rescued.
45322 */
45323
45324 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
45325 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT);
45326 DUK_DD(DUK_DDPRINT("object rescued during mark-and-sweep finalization: %p", (void *) curr));
45327#if defined(DUK_USE_DEBUG)
45328 count_rescue++;
45329#endif
45330 } else {
45331 /*
45332 * Plain, boring reachable object.
45333 */
45334 DUK_DD(DUK_DDPRINT("keep object: %!iO", curr));
45335 count_keep++;
45336 }
45337
45338 if (!heap->heap_allocated) {
45339 heap->heap_allocated = curr;
45340 }
45341 if (prev) {
45342 DUK_HEAPHDR_SET_NEXT(heap, prev, curr);
45343 }
45344#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
45345 DUK_HEAPHDR_SET_PREV(heap, curr, prev);
45346#endif
45347 DUK_ASSERT_HEAPHDR_LINKS(heap, prev);
45348 DUK_ASSERT_HEAPHDR_LINKS(heap, curr);
45349 prev = curr;
45350 }
45351
45352 DUK_HEAPHDR_CLEAR_REACHABLE(curr);
45353 DUK_HEAPHDR_CLEAR_FINALIZED(curr);
45354 DUK_HEAPHDR_CLEAR_FINALIZABLE(curr);
45355
45356 DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr));
45357 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
45358 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
45359
45360 curr = next;
45361 } else {
45362 /*
45363 * Unreachable object, free
45364 */
45365
45366 DUK_DDD(DUK_DDDPRINT("sweep, not reachable: %p", (void *) curr));
45367
45368#if defined(DUK_USE_REFERENCE_COUNTING)
45369 /* Non-zero refcounts should not happen because we refcount
45370 * finalize all unreachable objects which should cancel out
45371 * refcounts (even for cycles).
45372 */
45373 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(curr) == 0);
45374#endif
45375 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
45376
45377 if (DUK_HEAPHDR_HAS_FINALIZED(curr)) {
45378 DUK_DDD(DUK_DDDPRINT("finalized object not rescued: %p", (void *) curr));
45379 }
45380
45381 /* Note: object cannot be a finalizable unreachable object, as
45382 * they have been marked temporarily reachable for this round,
45383 * and are handled above.
45384 */
45385
45386#if defined(DUK_USE_DEBUG)
45387 count_free++;
45388#endif
45389
45390 /* weak refs should be handled here, but no weak refs for
45391 * any non-string objects exist right now.
45392 */
45393
45394 /* free object and all auxiliary (non-heap) allocs */
45395 duk_heap_free_heaphdr_raw(heap, curr);
45396
45397 curr = next;
45398 }
45399 }
45400 if (prev) {
45401 DUK_HEAPHDR_SET_NEXT(heap, prev, NULL);
45402 }
45403 DUK_ASSERT_HEAPHDR_LINKS(heap, prev);
45404
45405#if defined(DUK_USE_DEBUG)
45406 DUK_D(DUK_DPRINT("mark-and-sweep sweep objects (non-string): %ld freed, %ld kept, %ld rescued, %ld queued for finalization",
45407 (long) count_free, (long) count_keep, (long) count_rescue, (long) count_finalize));
45408#endif
45409 *out_count_keep = count_keep;
45410}
45411
45412/*
45413 * Run (object) finalizers in the "to be finalized" work list.
45414 */
45415
45416#if defined(DUK_USE_FINALIZER_SUPPORT)
45417DUK_LOCAL void duk__run_object_finalizers(duk_heap *heap, duk_small_uint_t flags) {
45418 duk_heaphdr *curr;
45419 duk_heaphdr *next;
45420#if defined(DUK_USE_DEBUG)
45421 duk_size_t count = 0;
45422#endif
45423 duk_hthread *thr;
45424
45425 DUK_DD(DUK_DDPRINT("duk__run_object_finalizers: %p", (void *) heap));
45426
45427 thr = duk__get_temp_hthread(heap);
45428 DUK_ASSERT(thr != NULL);
45429
45430 curr = heap->finalize_list;
45431 while (curr) {
45432 DUK_DDD(DUK_DDDPRINT("mark-and-sweep finalize: %p", (void *) curr));
45433
45434 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(curr) == DUK_HTYPE_OBJECT); /* only objects have finalizers */
45435 DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(curr)); /* flags have been already cleared */
45436 DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(curr));
45437 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(curr));
45438 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
45439 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY(curr)); /* No finalizers for ROM objects */
45440
45441 if (DUK_LIKELY((flags & DUK_MS_FLAG_SKIP_FINALIZERS) == 0)) {
45442 /* Run the finalizer, duk_hobject_run_finalizer() sets FINALIZED.
45443 * Next mark-and-sweep will collect the object unless it has
45444 * become reachable (i.e. rescued). FINALIZED prevents the
45445 * finalizer from being executed again before that.
45446 */
45447 duk_hobject_run_finalizer(thr, (duk_hobject *) curr); /* must never longjmp */
45448 DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(curr));
45449 } else {
45450 /* Used during heap destruction: don't actually run finalizers
45451 * because we're heading into forced finalization. Instead,
45452 * queue finalizable objects back to the heap_allocated list.
45453 */
45454 DUK_D(DUK_DPRINT("skip finalizers flag set, queue object to heap_allocated without finalizing"));
45455 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(curr));
45456 }
45457
45458 /* queue back to heap_allocated */
45459 next = DUK_HEAPHDR_GET_NEXT(heap, curr);
45460 DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, curr);
45461
45462 curr = next;
45463#if defined(DUK_USE_DEBUG)
45464 count++;
45465#endif
45466 }
45467
45468 /* finalize_list will always be processed completely */
45469 heap->finalize_list = NULL;
45470
45471#if defined(DUK_USE_DEBUG)
45472 DUK_D(DUK_DPRINT("mark-and-sweep finalize objects: %ld finalizers called", (long) count));
45473#endif
45474}
45475#endif /* DUK_USE_FINALIZER_SUPPORT */
45476
45477/*
45478 * Object compaction.
45479 *
45480 * Compaction is assumed to never throw an error.
45481 */
45482
45483DUK_LOCAL int duk__protected_compact_object(duk_context *ctx, void *udata) {
45484 duk_hobject *obj;
45485 /* XXX: for threads, compact value stack, call stack, catch stack? */
45486
45487 DUK_UNREF(udata);
45488 obj = duk_known_hobject(ctx, -1);
45489 duk_hobject_compact_props((duk_hthread *) ctx, obj);
45490 return 0;
45491}
45492
45493#if defined(DUK_USE_DEBUG)
45494DUK_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) {
45495#else
45496DUK_LOCAL void duk__compact_object_list(duk_heap *heap, duk_hthread *thr, duk_heaphdr *start) {
45497#endif
45498 duk_heaphdr *curr;
45499#if defined(DUK_USE_DEBUG)
45500 duk_size_t old_size, new_size;
45501#endif
45502 duk_hobject *obj;
45503
45504 DUK_UNREF(heap);
45505
45506 curr = start;
45507 while (curr) {
45508 DUK_DDD(DUK_DDDPRINT("mark-and-sweep compact: %p", (void *) curr));
45509
45510 if (DUK_HEAPHDR_GET_TYPE(curr) != DUK_HTYPE_OBJECT) {
45511 goto next;
45512 }
45513 obj = (duk_hobject *) curr;
45514
45515#if defined(DUK_USE_DEBUG)
45516 old_size = DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj),
45517 DUK_HOBJECT_GET_ASIZE(obj),
45518 DUK_HOBJECT_GET_HSIZE(obj));
45519#endif
45520
45521 DUK_DD(DUK_DDPRINT("compact object: %p", (void *) obj));
45522 duk_push_hobject((duk_context *) thr, obj);
45523 /* XXX: disable error handlers for duration of compaction? */
45524 duk_safe_call((duk_context *) thr, duk__protected_compact_object, NULL, 1, 0);
45525
45526#if defined(DUK_USE_DEBUG)
45527 new_size = DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj),
45528 DUK_HOBJECT_GET_ASIZE(obj),
45529 DUK_HOBJECT_GET_HSIZE(obj));
45530#endif
45531
45532#if defined(DUK_USE_DEBUG)
45533 (*p_count_compact)++;
45534 (*p_count_bytes_saved) += (duk_size_t) (old_size - new_size);
45535#endif
45536
45537 next:
45538 curr = DUK_HEAPHDR_GET_NEXT(heap, curr);
45539#if defined(DUK_USE_DEBUG)
45540 (*p_count_check)++;
45541#endif
45542 }
45543}
45544
45545DUK_LOCAL void duk__compact_objects(duk_heap *heap) {
45546 /* XXX: which lists should participate? to be finalized? */
45547#if defined(DUK_USE_DEBUG)
45548 duk_size_t count_check = 0;
45549 duk_size_t count_compact = 0;
45550 duk_size_t count_bytes_saved = 0;
45551#endif
45552 duk_hthread *thr;
45553
45554 DUK_DD(DUK_DDPRINT("duk__compact_objects: %p", (void *) heap));
45555
45556 thr = duk__get_temp_hthread(heap);
45557 DUK_ASSERT(thr != NULL);
45558
45559#if defined(DUK_USE_DEBUG)
45560 duk__compact_object_list(heap, thr, heap->heap_allocated, &count_check, &count_compact, &count_bytes_saved);
45561 duk__compact_object_list(heap, thr, heap->finalize_list, &count_check, &count_compact, &count_bytes_saved);
45562#if defined(DUK_USE_REFERENCE_COUNTING)
45563 duk__compact_object_list(heap, thr, heap->refzero_list, &count_check, &count_compact, &count_bytes_saved);
45564#endif
45565#else
45566 duk__compact_object_list(heap, thr, heap->heap_allocated);
45567 duk__compact_object_list(heap, thr, heap->finalize_list);
45568#if defined(DUK_USE_REFERENCE_COUNTING)
45569 duk__compact_object_list(heap, thr, heap->refzero_list);
45570#endif
45571#endif
45572
45573#if defined(DUK_USE_DEBUG)
45574 DUK_D(DUK_DPRINT("mark-and-sweep compact objects: %ld checked, %ld compaction attempts, %ld bytes saved by compaction",
45575 (long) count_check, (long) count_compact, (long) count_bytes_saved));
45576#endif
45577}
45578
45579/*
45580 * Assertion helpers.
45581 */
45582
45583#if defined(DUK_USE_ASSERTIONS)
45584DUK_LOCAL void duk__assert_heaphdr_flags(duk_heap *heap) {
45585 duk_heaphdr *hdr;
45586
45587 hdr = heap->heap_allocated;
45588 while (hdr) {
45589 DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(hdr));
45590 DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr));
45591 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr));
45592 /* may have FINALIZED */
45593 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
45594 }
45595
45596#if defined(DUK_USE_REFERENCE_COUNTING)
45597 hdr = heap->refzero_list;
45598 while (hdr) {
45599 DUK_ASSERT(!DUK_HEAPHDR_HAS_REACHABLE(hdr));
45600 DUK_ASSERT(!DUK_HEAPHDR_HAS_TEMPROOT(hdr));
45601 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(hdr));
45602 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZED(hdr));
45603 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
45604 }
45605#endif /* DUK_USE_REFERENCE_COUNTING */
45606}
45607
45608#if defined(DUK_USE_REFERENCE_COUNTING)
45609DUK_LOCAL void duk__assert_valid_refcounts(duk_heap *heap) {
45610 duk_heaphdr *hdr = heap->heap_allocated;
45611 while (hdr) {
45612 if (DUK_HEAPHDR_GET_REFCOUNT(hdr) == 0 &&
45613 DUK_HEAPHDR_HAS_FINALIZED(hdr)) {
45614 /* An object may be in heap_allocated list with a zero
45615 * refcount if it has just been finalized and is waiting
45616 * to be collected by the next cycle.
45617 */
45618 } else if (DUK_HEAPHDR_GET_REFCOUNT(hdr) == 0) {
45619 /* An object may be in heap_allocated list with a zero
45620 * refcount also if it is a temporary object created by
45621 * a finalizer; because finalization now runs inside
45622 * mark-and-sweep, such objects will not be queued to
45623 * refzero_list and will thus appear here with refcount
45624 * zero.
45625 */
45626#if 0 /* this case can no longer occur because refcount is unsigned */
45627 } else if (DUK_HEAPHDR_GET_REFCOUNT(hdr) < 0) {
45628 DUK_D(DUK_DPRINT("invalid refcount: %ld, %p -> %!O",
45629 (hdr != NULL ? (long) DUK_HEAPHDR_GET_REFCOUNT(hdr) : (long) 0),
45630 (void *) hdr, (duk_heaphdr *) hdr));
45631 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(hdr) > 0);
45632#endif
45633 }
45634 hdr = DUK_HEAPHDR_GET_NEXT(heap, hdr);
45635 }
45636}
45637#endif /* DUK_USE_REFERENCE_COUNTING */
45638#endif /* DUK_USE_ASSERTIONS */
45639
45640/*
45641 * Finalizer torture. Do one fake finalizer call which causes side effects
45642 * similar to one or more finalizers on actual objects.
45643 */
45644
45645#if defined(DUK_USE_FINALIZER_SUPPORT)
45646#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE)
45647DUK_LOCAL duk_ret_t duk__markandsweep_fake_finalizer(duk_context *ctx) {
45648 DUK_D(DUK_DPRINT("fake mark-and-sweep torture finalizer executed"));
45649
45650 /* Require a lot of stack to force a value stack grow/shrink.
45651 * Recursive mark-and-sweep is prevented by allocation macros
45652 * so this won't trigger another mark-and-sweep.
45653 */
45654 duk_require_stack(ctx, 100000);
45655
45656 /* XXX: do something to force a callstack grow/shrink, perhaps
45657 * just a manual forced resize or a forced relocating realloc?
45658 */
45659
45660 return 0;
45661}
45662
45663DUK_LOCAL void duk__markandsweep_torture_finalizer(duk_hthread *thr) {
45664 duk_context *ctx;
45665 duk_int_t rc;
45666
45667 DUK_ASSERT(thr != NULL);
45668 ctx = (duk_context *) thr;
45669
45670 /* Avoid fake finalization when callstack limit has been reached.
45671 * Otherwise a callstack limit error will be created, then refzero'ed.
45672 */
45673 if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit ||
45674 thr->callstack_size + 2 * DUK_CALLSTACK_GROW_STEP >= thr->callstack_max /*approximate*/) {
45675 DUK_D(DUK_DPRINT("call recursion depth reached, avoid fake mark-and-sweep torture finalizer"));
45676 return;
45677 }
45678
45679 /* Run fake finalizer. Avoid creating unnecessary garbage. */
45680 duk_push_c_function(ctx, duk__markandsweep_fake_finalizer, 0 /*nargs*/);
45681 rc = duk_pcall(ctx, 0 /*nargs*/);
45682 DUK_UNREF(rc); /* ignored */
45683 duk_pop(ctx);
45684}
45685#endif /* DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE */
45686#endif /* DUK_USE_FINALIZER_SUPPORT */
45687
45688/*
45689 * Main mark-and-sweep function.
45690 *
45691 * 'flags' represents the features requested by the caller. The current
45692 * heap->mark_and_sweep_base_flags is ORed automatically into the flags;
45693 * the base flags mask typically prevents certain mark-and-sweep operations
45694 * to avoid trouble.
45695 */
45696
45697DUK_INTERNAL duk_bool_t duk_heap_mark_and_sweep(duk_heap *heap, duk_small_uint_t flags) {
45698 duk_hthread *thr;
45699 duk_size_t count_keep_obj;
45700 duk_size_t count_keep_str;
45701#if defined(DUK_USE_VOLUNTARY_GC)
45702 duk_size_t tmp;
45703#endif
45704
45705 /* XXX: thread selection for mark-and-sweep is currently a hack.
45706 * If we don't have a thread, the entire mark-and-sweep is now
45707 * skipped (although we could just skip finalizations).
45708 */
45709
45710 /* If thr != NULL, the thr may still be in the middle of
45711 * initialization.
45712 * XXX: Improve the thread viability test.
45713 */
45714 thr = duk__get_temp_hthread(heap);
45715 if (thr == NULL) {
45716 DUK_D(DUK_DPRINT("gc skipped because we don't have a temp thread"));
45717
45718 /* reset voluntary gc trigger count */
45719#if defined(DUK_USE_VOLUNTARY_GC)
45720 heap->mark_and_sweep_trigger_counter = DUK_HEAP_MARK_AND_SWEEP_TRIGGER_SKIP;
45721#endif
45722 return 0; /* OK */
45723 }
45724
45725 /* If debugger is paused, garbage collection is disabled by default. */
45726 /* XXX: will need a force flag if garbage collection is triggered
45727 * explicitly during paused state.
45728 */
45729#if defined(DUK_USE_DEBUGGER_SUPPORT)
45730 if (DUK_HEAP_IS_PAUSED(heap)) {
45731 /* Checking this here rather that in memory alloc primitives
45732 * reduces checking code there but means a failed allocation
45733 * will go through a few retries before giving up. That's
45734 * fine because this only happens during debugging.
45735 */
45736 DUK_D(DUK_DPRINT("gc skipped because debugger is paused"));
45737 return 0;
45738 }
45739#endif
45740
45741 DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) starting, requested flags: 0x%08lx, effective flags: 0x%08lx",
45742 (unsigned long) flags, (unsigned long) (flags | heap->mark_and_sweep_base_flags)));
45743
45744 flags |= heap->mark_and_sweep_base_flags;
45745
45746 /*
45747 * Assertions before
45748 */
45749
45750#if defined(DUK_USE_ASSERTIONS)
45751 DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap));
45752 DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap));
45753 DUK_ASSERT(heap->mark_and_sweep_recursion_depth == 0);
45754 duk__assert_heaphdr_flags(heap);
45755#if defined(DUK_USE_REFERENCE_COUNTING)
45756 /* Note: DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) may be true; a refcount
45757 * finalizer may trigger a mark-and-sweep.
45758 */
45759 duk__assert_valid_refcounts(heap);
45760#endif /* DUK_USE_REFERENCE_COUNTING */
45761#endif /* DUK_USE_ASSERTIONS */
45762
45763 /*
45764 * Begin
45765 */
45766
45767 DUK_HEAP_SET_MARKANDSWEEP_RUNNING(heap);
45768
45769 /*
45770 * Mark roots, hoping that recursion limit is not normally hit.
45771 * If recursion limit is hit, run additional reachability rounds
45772 * starting from "temproots" until marking is complete.
45773 *
45774 * Marking happens in two phases: first we mark actual reachability
45775 * roots (and run "temproots" to complete the process). Then we
45776 * check which objects are unreachable and are finalizable; such
45777 * objects are marked as FINALIZABLE and marked as reachability
45778 * (and "temproots" is run again to complete the process).
45779 *
45780 * The heap finalize_list must also be marked as a reachability root.
45781 * There may be objects on the list from a previous round if the
45782 * previous run had finalizer skip flag.
45783 */
45784
45785 duk__mark_roots_heap(heap); /* main reachability roots */
45786#if defined(DUK_USE_REFERENCE_COUNTING)
45787 duk__mark_refzero_list(heap); /* refzero_list treated as reachability roots */
45788#endif
45789 duk__mark_temproots_by_heap_scan(heap); /* temproots */
45790
45791#if defined(DUK_USE_FINALIZER_SUPPORT)
45792 duk__mark_finalizable(heap); /* mark finalizable as reachability roots */
45793 duk__mark_finalize_list(heap); /* mark finalizer work list as reachability roots */
45794#endif
45795 duk__mark_temproots_by_heap_scan(heap); /* temproots */
45796
45797 /*
45798 * Sweep garbage and remove marking flags, and move objects with
45799 * finalizers to the finalizer work list.
45800 *
45801 * Objects to be swept need to get their refcounts finalized before
45802 * they are swept. In other words, their target object refcounts
45803 * need to be decreased. This has to be done before freeing any
45804 * objects to avoid decref'ing dangling pointers (which may happen
45805 * even without bugs, e.g. with reference loops)
45806 *
45807 * Because strings don't point to other heap objects, similar
45808 * finalization is not necessary for strings.
45809 */
45810
45811 /* XXX: more emergency behavior, e.g. find smaller hash sizes etc */
45812
45813#if defined(DUK_USE_REFERENCE_COUNTING)
45814 duk__finalize_refcounts(heap);
45815#endif
45816 duk__sweep_heap(heap, flags, &count_keep_obj);
45817#if defined(DUK_USE_STRTAB_CHAIN)
45818 duk__sweep_stringtable_chain(heap, &count_keep_str);
45819#elif defined(DUK_USE_STRTAB_PROBE)
45820 duk__sweep_stringtable_probe(heap, &count_keep_str);
45821#else
45822#error internal error, invalid strtab options
45823#endif
45824#if defined(DUK_USE_REFERENCE_COUNTING)
45825 duk__clear_refzero_list_flags(heap);
45826#endif
45827#if defined(DUK_USE_FINALIZER_SUPPORT)
45828 duk__clear_finalize_list_flags(heap);
45829#endif
45830
45831 /*
45832 * Object compaction (emergency only).
45833 *
45834 * Object compaction is a separate step after sweeping, as there is
45835 * more free memory for it to work with. Also, currently compaction
45836 * may insert new objects into the heap allocated list and the string
45837 * table which we don't want to do during a sweep (the reachability
45838 * flags of such objects would be incorrect). The objects inserted
45839 * are currently:
45840 *
45841 * - a temporary duk_hbuffer for a new properties allocation
45842 * - if array part is abandoned, string keys are interned
45843 *
45844 * The object insertions go to the front of the list, so they do not
45845 * cause an infinite loop (they are not compacted).
45846 */
45847
45848 if ((flags & DUK_MS_FLAG_EMERGENCY) &&
45849 !(flags & DUK_MS_FLAG_NO_OBJECT_COMPACTION)) {
45850 duk__compact_objects(heap);
45851 }
45852
45853 /*
45854 * String table resize check.
45855 *
45856 * Note: this may silently (and safely) fail if GC is caused by an
45857 * allocation call in stringtable resize_hash(). Resize_hash()
45858 * will prevent a recursive call to itself by setting the
45859 * DUK_MS_FLAG_NO_STRINGTABLE_RESIZE in heap->mark_and_sweep_base_flags.
45860 */
45861
45862 /* XXX: stringtable emergency compaction? */
45863
45864 /* XXX: remove this feature entirely? it would only matter for
45865 * emergency GC. Disable for lowest memory builds.
45866 */
45867#if defined(DUK_USE_MS_STRINGTABLE_RESIZE)
45868 if (!(flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE)) {
45869 DUK_DD(DUK_DDPRINT("resize stringtable: %p", (void *) heap));
45870 duk_heap_force_strtab_resize(heap);
45871 } else {
45872 DUK_D(DUK_DPRINT("stringtable resize skipped because DUK_MS_FLAG_NO_STRINGTABLE_RESIZE is set"));
45873 }
45874#endif
45875
45876 /*
45877 * Finalize objects in the finalization work list. Finalized
45878 * objects are queued back to heap_allocated with FINALIZED set.
45879 *
45880 * Since finalizers may cause arbitrary side effects, they are
45881 * prevented during string table and object property allocation
45882 * resizing using the DUK_MS_FLAG_NO_FINALIZERS flag in
45883 * heap->mark_and_sweep_base_flags. In this case the objects
45884 * remain in the finalization work list after mark-and-sweep
45885 * exits and they may be finalized on the next pass.
45886 *
45887 * Finalization currently happens inside "MARKANDSWEEP_RUNNING"
45888 * protection (no mark-and-sweep may be triggered by the
45889 * finalizers). As a side effect:
45890 *
45891 * 1) an out-of-memory error inside a finalizer will not
45892 * cause a mark-and-sweep and may cause the finalizer
45893 * to fail unnecessarily
45894 *
45895 * 2) any temporary objects whose refcount decreases to zero
45896 * during finalization will not be put into refzero_list;
45897 * they can only be collected by another mark-and-sweep
45898 *
45899 * This is not optimal, but since the sweep for this phase has
45900 * already happened, this is probably good enough for now.
45901 */
45902
45903#if defined(DUK_USE_FINALIZER_SUPPORT)
45904#if defined(DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE)
45905 /* Cannot simulate individual finalizers because finalize_list only
45906 * contains objects with actual finalizers. But simulate side effects
45907 * from finalization by doing a bogus function call and resizing the
45908 * stacks.
45909 */
45910 if (flags & DUK_MS_FLAG_NO_FINALIZERS) {
45911 DUK_D(DUK_DPRINT("skip mark-and-sweep torture finalizer, DUK_MS_FLAG_NO_FINALIZERS is set"));
45912 } else if (!(thr->valstack != NULL && thr->callstack != NULL && thr->catchstack != NULL)) {
45913 DUK_D(DUK_DPRINT("skip mark-and-sweep torture finalizer, thread not yet viable"));
45914 } else {
45915 DUK_D(DUK_DPRINT("run mark-and-sweep torture finalizer"));
45916 duk__markandsweep_torture_finalizer(thr);
45917 }
45918#endif /* DUK_USE_MARKANDSWEEP_FINALIZER_TORTURE */
45919
45920 if (flags & DUK_MS_FLAG_NO_FINALIZERS) {
45921 DUK_D(DUK_DPRINT("finalizer run skipped because DUK_MS_FLAG_NO_FINALIZERS is set"));
45922 } else {
45923 duk__run_object_finalizers(heap, flags);
45924 }
45925#endif /* DUK_USE_FINALIZER_SUPPORT */
45926
45927 /*
45928 * Finish
45929 */
45930
45931 DUK_HEAP_CLEAR_MARKANDSWEEP_RUNNING(heap);
45932
45933 /*
45934 * Assertions after
45935 */
45936
45937#if defined(DUK_USE_ASSERTIONS)
45938 DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap));
45939 DUK_ASSERT(!DUK_HEAP_HAS_MARKANDSWEEP_RECLIMIT_REACHED(heap));
45940 DUK_ASSERT(heap->mark_and_sweep_recursion_depth == 0);
45941 duk__assert_heaphdr_flags(heap);
45942#if defined(DUK_USE_REFERENCE_COUNTING)
45943 /* Note: DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap) may be true; a refcount
45944 * finalizer may trigger a mark-and-sweep.
45945 */
45946 duk__assert_valid_refcounts(heap);
45947#endif /* DUK_USE_REFERENCE_COUNTING */
45948#endif /* DUK_USE_ASSERTIONS */
45949
45950 /*
45951 * Reset trigger counter
45952 */
45953
45954#if defined(DUK_USE_VOLUNTARY_GC)
45955 tmp = (count_keep_obj + count_keep_str) / 256;
45956 heap->mark_and_sweep_trigger_counter = (duk_int_t) (
45957 (tmp * DUK_HEAP_MARK_AND_SWEEP_TRIGGER_MULT) +
45958 DUK_HEAP_MARK_AND_SWEEP_TRIGGER_ADD);
45959 DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, trigger reset to %ld",
45960 (long) count_keep_obj, (long) count_keep_str, (long) heap->mark_and_sweep_trigger_counter));
45961#else
45962 DUK_D(DUK_DPRINT("garbage collect (mark-and-sweep) finished: %ld objects kept, %ld strings kept, no voluntary trigger",
45963 (long) count_keep_obj, (long) count_keep_str));
45964#endif
45965
45966 return 0; /* OK */
45967}
45968/*
45969 * Memory allocation handling.
45970 */
45971
45972/* #include duk_internal.h -> already included */
45973
45974/*
45975 * Helpers
45976 *
45977 * The fast path checks are done within a macro to ensure "inlining"
45978 * while the slow path actions use a helper (which won't typically be
45979 * inlined in size optimized builds).
45980 */
45981
45982#if defined(DUK_USE_VOLUNTARY_GC)
45983#define DUK__VOLUNTARY_PERIODIC_GC(heap) do { \
45984 (heap)->mark_and_sweep_trigger_counter--; \
45985 if ((heap)->mark_and_sweep_trigger_counter <= 0) { \
45986 duk__run_voluntary_gc(heap); \
45987 } \
45988 } while (0)
45989
45990DUK_LOCAL void duk__run_voluntary_gc(duk_heap *heap) {
45991 if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
45992 DUK_DD(DUK_DDPRINT("mark-and-sweep in progress -> skip voluntary mark-and-sweep now"));
45993 } else {
45994 duk_small_uint_t flags;
45995 duk_bool_t rc;
45996
45997 DUK_D(DUK_DPRINT("triggering voluntary mark-and-sweep"));
45998 flags = 0;
45999 rc = duk_heap_mark_and_sweep(heap, flags);
46000 DUK_UNREF(rc);
46001 }
46002}
46003#else
46004#define DUK__VOLUNTARY_PERIODIC_GC(heap) /* no voluntary gc */
46005#endif /* DUK_USE_VOLUNTARY_GC */
46006
46007/*
46008 * Allocate memory with garbage collection
46009 */
46010
46011DUK_INTERNAL void *duk_heap_mem_alloc(duk_heap *heap, duk_size_t size) {
46012 void *res;
46013 duk_bool_t rc;
46014 duk_small_int_t i;
46015
46016 DUK_ASSERT(heap != NULL);
46017 DUK_ASSERT_DISABLE(size >= 0);
46018
46019 /*
46020 * Voluntary periodic GC (if enabled)
46021 */
46022
46023 DUK__VOLUNTARY_PERIODIC_GC(heap);
46024
46025 /*
46026 * First attempt
46027 */
46028
46029#if defined(DUK_USE_GC_TORTURE)
46030 /* simulate alloc failure on every alloc (except when mark-and-sweep is running) */
46031 if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
46032 DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first alloc attempt fails"));
46033 res = NULL;
46034 DUK_UNREF(res);
46035 goto skip_attempt;
46036 }
46037#endif
46038 res = heap->alloc_func(heap->heap_udata, size);
46039 if (res || size == 0) {
46040 /* for zero size allocations NULL is allowed */
46041 return res;
46042 }
46043#if defined(DUK_USE_GC_TORTURE)
46044 skip_attempt:
46045#endif
46046
46047 DUK_D(DUK_DPRINT("first alloc attempt failed, attempt to gc and retry"));
46048
46049 /*
46050 * Avoid a GC if GC is already running. This can happen at a late
46051 * stage in a GC when we try to e.g. resize the stringtable
46052 * or compact objects.
46053 */
46054
46055 if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
46056 DUK_D(DUK_DPRINT("duk_heap_mem_alloc() failed, gc in progress (gc skipped), alloc size %ld", (long) size));
46057 return NULL;
46058 }
46059
46060 /*
46061 * Retry with several GC attempts. Initial attempts are made without
46062 * emergency mode; later attempts use emergency mode which minimizes
46063 * memory allocations forcibly.
46064 */
46065
46066 for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) {
46067 duk_small_uint_t flags;
46068
46069 flags = 0;
46070 if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) {
46071 flags |= DUK_MS_FLAG_EMERGENCY;
46072 }
46073
46074 rc = duk_heap_mark_and_sweep(heap, flags);
46075 DUK_UNREF(rc);
46076
46077 res = heap->alloc_func(heap->heap_udata, size);
46078 if (res) {
46079 DUK_D(DUK_DPRINT("duk_heap_mem_alloc() succeeded after gc (pass %ld), alloc size %ld",
46080 (long) (i + 1), (long) size));
46081 return res;
46082 }
46083 }
46084
46085 DUK_D(DUK_DPRINT("duk_heap_mem_alloc() failed even after gc, alloc size %ld", (long) size));
46086 return NULL;
46087}
46088
46089DUK_INTERNAL void *duk_heap_mem_alloc_zeroed(duk_heap *heap, duk_size_t size) {
46090 void *res;
46091
46092 DUK_ASSERT(heap != NULL);
46093 DUK_ASSERT_DISABLE(size >= 0);
46094
46095 res = DUK_ALLOC(heap, size);
46096 if (res) {
46097 /* assume memset with zero size is OK */
46098 DUK_MEMZERO(res, size);
46099 }
46100 return res;
46101}
46102
46103/*
46104 * Reallocate memory with garbage collection
46105 */
46106
46107DUK_INTERNAL void *duk_heap_mem_realloc(duk_heap *heap, void *ptr, duk_size_t newsize) {
46108 void *res;
46109 duk_bool_t rc;
46110 duk_small_int_t i;
46111
46112 DUK_ASSERT(heap != NULL);
46113 /* ptr may be NULL */
46114 DUK_ASSERT_DISABLE(newsize >= 0);
46115
46116 /*
46117 * Voluntary periodic GC (if enabled)
46118 */
46119
46120 DUK__VOLUNTARY_PERIODIC_GC(heap);
46121
46122 /*
46123 * First attempt
46124 */
46125
46126#if defined(DUK_USE_GC_TORTURE)
46127 /* simulate alloc failure on every realloc (except when mark-and-sweep is running) */
46128 if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
46129 DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first realloc attempt fails"));
46130 res = NULL;
46131 DUK_UNREF(res);
46132 goto skip_attempt;
46133 }
46134#endif
46135 res = heap->realloc_func(heap->heap_udata, ptr, newsize);
46136 if (res || newsize == 0) {
46137 /* for zero size allocations NULL is allowed */
46138 return res;
46139 }
46140#if defined(DUK_USE_GC_TORTURE)
46141 skip_attempt:
46142#endif
46143
46144 DUK_D(DUK_DPRINT("first realloc attempt failed, attempt to gc and retry"));
46145
46146 /*
46147 * Avoid a GC if GC is already running. See duk_heap_mem_alloc().
46148 */
46149
46150 if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
46151 DUK_D(DUK_DPRINT("duk_heap_mem_realloc() failed, gc in progress (gc skipped), alloc size %ld", (long) newsize));
46152 return NULL;
46153 }
46154
46155 /*
46156 * Retry with several GC attempts. Initial attempts are made without
46157 * emergency mode; later attempts use emergency mode which minimizes
46158 * memory allocations forcibly.
46159 */
46160
46161 for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) {
46162 duk_small_uint_t flags;
46163
46164 flags = 0;
46165 if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) {
46166 flags |= DUK_MS_FLAG_EMERGENCY;
46167 }
46168
46169 rc = duk_heap_mark_and_sweep(heap, flags);
46170 DUK_UNREF(rc);
46171
46172 res = heap->realloc_func(heap->heap_udata, ptr, newsize);
46173 if (res || newsize == 0) {
46174 DUK_D(DUK_DPRINT("duk_heap_mem_realloc() succeeded after gc (pass %ld), alloc size %ld",
46175 (long) (i + 1), (long) newsize));
46176 return res;
46177 }
46178 }
46179
46180 DUK_D(DUK_DPRINT("duk_heap_mem_realloc() failed even after gc, alloc size %ld", (long) newsize));
46181 return NULL;
46182}
46183
46184/*
46185 * Reallocate memory with garbage collection, using a callback to provide
46186 * the current allocated pointer. This variant is used when a mark-and-sweep
46187 * (e.g. finalizers) might change the original pointer.
46188 */
46189
46190DUK_INTERNAL void *duk_heap_mem_realloc_indirect(duk_heap *heap, duk_mem_getptr cb, void *ud, duk_size_t newsize) {
46191 void *res;
46192 duk_bool_t rc;
46193 duk_small_int_t i;
46194
46195 DUK_ASSERT(heap != NULL);
46196 DUK_ASSERT_DISABLE(newsize >= 0);
46197
46198 /*
46199 * Voluntary periodic GC (if enabled)
46200 */
46201
46202 DUK__VOLUNTARY_PERIODIC_GC(heap);
46203
46204 /*
46205 * First attempt
46206 */
46207
46208#if defined(DUK_USE_GC_TORTURE)
46209 /* simulate alloc failure on every realloc (except when mark-and-sweep is running) */
46210 if (!DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
46211 DUK_DDD(DUK_DDDPRINT("gc torture enabled, pretend that first indirect realloc attempt fails"));
46212 res = NULL;
46213 DUK_UNREF(res);
46214 goto skip_attempt;
46215 }
46216#endif
46217 res = heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize);
46218 if (res || newsize == 0) {
46219 /* for zero size allocations NULL is allowed */
46220 return res;
46221 }
46222#if defined(DUK_USE_GC_TORTURE)
46223 skip_attempt:
46224#endif
46225
46226 DUK_D(DUK_DPRINT("first indirect realloc attempt failed, attempt to gc and retry"));
46227
46228 /*
46229 * Avoid a GC if GC is already running. See duk_heap_mem_alloc().
46230 */
46231
46232 if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) {
46233 DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() failed, gc in progress (gc skipped), alloc size %ld", (long) newsize));
46234 return NULL;
46235 }
46236
46237 /*
46238 * Retry with several GC attempts. Initial attempts are made without
46239 * emergency mode; later attempts use emergency mode which minimizes
46240 * memory allocations forcibly.
46241 */
46242
46243 for (i = 0; i < DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_LIMIT; i++) {
46244 duk_small_uint_t flags;
46245
46246#if defined(DUK_USE_ASSERTIONS)
46247 void *ptr_pre; /* ptr before mark-and-sweep */
46248 void *ptr_post;
46249#endif
46250
46251#if defined(DUK_USE_ASSERTIONS)
46252 ptr_pre = cb(heap, ud);
46253#endif
46254 flags = 0;
46255 if (i >= DUK_HEAP_ALLOC_FAIL_MARKANDSWEEP_EMERGENCY_LIMIT - 1) {
46256 flags |= DUK_MS_FLAG_EMERGENCY;
46257 }
46258
46259 rc = duk_heap_mark_and_sweep(heap, flags);
46260 DUK_UNREF(rc);
46261#if defined(DUK_USE_ASSERTIONS)
46262 ptr_post = cb(heap, ud);
46263 if (ptr_pre != ptr_post) {
46264 /* useful for debugging */
46265 DUK_DD(DUK_DDPRINT("note: base pointer changed by mark-and-sweep: %p -> %p",
46266 (void *) ptr_pre, (void *) ptr_post));
46267 }
46268#endif
46269
46270 /* Note: key issue here is to re-lookup the base pointer on every attempt.
46271 * The pointer being reallocated may change after every mark-and-sweep.
46272 */
46273
46274 res = heap->realloc_func(heap->heap_udata, cb(heap, ud), newsize);
46275 if (res || newsize == 0) {
46276 DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() succeeded after gc (pass %ld), alloc size %ld",
46277 (long) (i + 1), (long) newsize));
46278 return res;
46279 }
46280 }
46281
46282 DUK_D(DUK_DPRINT("duk_heap_mem_realloc_indirect() failed even after gc, alloc size %ld", (long) newsize));
46283 return NULL;
46284}
46285
46286/*
46287 * Free memory
46288 */
46289
46290DUK_INTERNAL void duk_heap_mem_free(duk_heap *heap, void *ptr) {
46291 DUK_ASSERT(heap != NULL);
46292 /* ptr may be NULL */
46293
46294 /* Must behave like a no-op with NULL and any pointer returned from
46295 * malloc/realloc with zero size.
46296 */
46297 heap->free_func(heap->heap_udata, ptr);
46298
46299 /* Count free operations toward triggering a GC but never actually trigger
46300 * a GC from a free. Otherwise code which frees internal structures would
46301 * need to put in NULLs at every turn to ensure the object is always in
46302 * consistent state for a mark-and-sweep.
46303 */
46304#if defined(DUK_USE_VOLUNTARY_GC)
46305 heap->mark_and_sweep_trigger_counter--;
46306#endif
46307}
46308
46309/* automatic undefs */
46310#undef DUK__VOLUNTARY_PERIODIC_GC
46311/*
46312 * Support functions for duk_heap.
46313 */
46314
46315/* #include duk_internal.h -> already included */
46316
46317#if defined(DUK_USE_DOUBLE_LINKED_HEAP) && defined(DUK_USE_REFERENCE_COUNTING)
46318/* arbitrary remove only works with double linked heap, and is only required by
46319 * reference counting so far.
46320 */
46321DUK_INTERNAL void duk_heap_remove_any_from_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) {
46322 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING);
46323
46324 if (DUK_HEAPHDR_GET_PREV(heap, hdr)) {
46325 DUK_HEAPHDR_SET_NEXT(heap, DUK_HEAPHDR_GET_PREV(heap, hdr), DUK_HEAPHDR_GET_NEXT(heap, hdr));
46326 } else {
46327 heap->heap_allocated = DUK_HEAPHDR_GET_NEXT(heap, hdr);
46328 }
46329 if (DUK_HEAPHDR_GET_NEXT(heap, hdr)) {
46330 DUK_HEAPHDR_SET_PREV(heap, DUK_HEAPHDR_GET_NEXT(heap, hdr), DUK_HEAPHDR_GET_PREV(heap, hdr));
46331 } else {
46332 ;
46333 }
46334
46335 /* The prev/next pointers of the removed duk_heaphdr are left as garbage.
46336 * It's up to the caller to ensure they're written before inserting the
46337 * object back.
46338 */
46339}
46340#endif
46341
46342DUK_INTERNAL void duk_heap_insert_into_heap_allocated(duk_heap *heap, duk_heaphdr *hdr) {
46343 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(hdr) != DUK_HTYPE_STRING);
46344
46345#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
46346 if (heap->heap_allocated) {
46347 DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, heap->heap_allocated) == NULL);
46348 DUK_HEAPHDR_SET_PREV(heap, heap->heap_allocated, hdr);
46349 }
46350 DUK_HEAPHDR_SET_PREV(heap, hdr, NULL);
46351#endif
46352 DUK_HEAPHDR_SET_NEXT(heap, hdr, heap->heap_allocated);
46353 heap->heap_allocated = hdr;
46354}
46355
46356#if defined(DUK_USE_INTERRUPT_COUNTER)
46357DUK_INTERNAL void duk_heap_switch_thread(duk_heap *heap, duk_hthread *new_thr) {
46358 duk_hthread *curr_thr;
46359
46360 DUK_ASSERT(heap != NULL);
46361
46362 if (new_thr != NULL) {
46363 curr_thr = heap->curr_thread;
46364 if (curr_thr == NULL) {
46365 /* For initial entry use default value; zero forces an
46366 * interrupt before executing the first insturction.
46367 */
46368 DUK_DD(DUK_DDPRINT("switch thread, initial entry, init default interrupt counter"));
46369 new_thr->interrupt_counter = 0;
46370 new_thr->interrupt_init = 0;
46371 } else {
46372 /* Copy interrupt counter/init value state to new thread (if any).
46373 * It's OK for new_thr to be the same as curr_thr.
46374 */
46375#if defined(DUK_USE_DEBUG)
46376 if (new_thr != curr_thr) {
46377 DUK_DD(DUK_DDPRINT("switch thread, not initial entry, copy interrupt counter"));
46378 }
46379#endif
46380 new_thr->interrupt_counter = curr_thr->interrupt_counter;
46381 new_thr->interrupt_init = curr_thr->interrupt_init;
46382 }
46383 } else {
46384 DUK_DD(DUK_DDPRINT("switch thread, new thread is NULL, no interrupt counter changes"));
46385 }
46386
46387 heap->curr_thread = new_thr; /* may be NULL */
46388}
46389#endif /* DUK_USE_INTERRUPT_COUNTER */
46390/*
46391 * Reference counting implementation.
46392 */
46393
46394/* #include duk_internal.h -> already included */
46395
46396#if defined(DUK_USE_REFERENCE_COUNTING)
46397
46398#if !defined(DUK_USE_DOUBLE_LINKED_HEAP)
46399#error internal error, reference counting requires a double linked heap
46400#endif
46401
46402/*
46403 * Misc
46404 */
46405
46406DUK_LOCAL void duk__queue_refzero(duk_heap *heap, duk_heaphdr *hdr) {
46407 /* tail insert: don't disturb head in case refzero is running */
46408
46409 if (heap->refzero_list != NULL) {
46410 duk_heaphdr *hdr_prev;
46411
46412 hdr_prev = heap->refzero_list_tail;
46413 DUK_ASSERT(hdr_prev != NULL);
46414 DUK_ASSERT(DUK_HEAPHDR_GET_NEXT(heap, hdr_prev) == NULL);
46415
46416 DUK_HEAPHDR_SET_NEXT(heap, hdr, NULL);
46417 DUK_HEAPHDR_SET_PREV(heap, hdr, hdr_prev);
46418 DUK_HEAPHDR_SET_NEXT(heap, hdr_prev, hdr);
46419 DUK_ASSERT_HEAPHDR_LINKS(heap, hdr);
46420 DUK_ASSERT_HEAPHDR_LINKS(heap, hdr_prev);
46421 heap->refzero_list_tail = hdr;
46422 } else {
46423 DUK_ASSERT(heap->refzero_list_tail == NULL);
46424 DUK_HEAPHDR_SET_NEXT(heap, hdr, NULL);
46425 DUK_HEAPHDR_SET_PREV(heap, hdr, NULL);
46426 DUK_ASSERT_HEAPHDR_LINKS(heap, hdr);
46427 heap->refzero_list = hdr;
46428 heap->refzero_list_tail = hdr;
46429 }
46430}
46431
46432/*
46433 * Heap object refcount finalization.
46434 *
46435 * When an object is about to be freed, all other objects it refers to must
46436 * be decref'd. Refcount finalization does NOT free the object or its inner
46437 * allocations (mark-and-sweep shares these helpers), it just manipulates
46438 * the refcounts.
46439 *
46440 * Note that any of the decref's may cause a refcount to drop to zero, BUT
46441 * it will not be processed inline. If refcount finalization is triggered
46442 * by refzero processing, the objects will be just queued to the refzero
46443 * list and processed later which eliminates C recursion. If refcount
46444 * finalization is triggered by mark-and-sweep, any refzero situations are
46445 * ignored because mark-and-sweep will deal with them. NORZ variants can
46446 * be used here in both cases.
46447 */
46448
46449DUK_LOCAL void duk__refcount_finalize_hobject(duk_hthread *thr, duk_hobject *h) {
46450 duk_uint_fast32_t i;
46451 duk_uint_fast32_t n;
46452 duk_propvalue *p_val;
46453 duk_tval *p_tv;
46454 duk_hstring **p_key;
46455 duk_uint8_t *p_flag;
46456
46457 DUK_ASSERT(h);
46458 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE((duk_heaphdr *) h) == DUK_HTYPE_OBJECT);
46459
46460 /* XXX: better to get base and walk forwards? */
46461
46462 p_key = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, h);
46463 p_val = DUK_HOBJECT_E_GET_VALUE_BASE(thr->heap, h);
46464 p_flag = DUK_HOBJECT_E_GET_FLAGS_BASE(thr->heap, h);
46465 n = DUK_HOBJECT_GET_ENEXT(h);
46466 while (n-- > 0) {
46468
46469 key = p_key[n];
46470 if (!key) {
46471 continue;
46472 }
46473 DUK_HSTRING_DECREF_NORZ(thr, key);
46474 if (p_flag[n] & DUK_PROPDESC_FLAG_ACCESSOR) {
46475 duk_hobject *h_getset;
46476 h_getset = p_val[n].a.get;
46477 DUK_ASSERT(h_getset == NULL || DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_getset));
46478 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, h_getset);
46479 h_getset = p_val[n].a.set;
46480 DUK_ASSERT(h_getset == NULL || DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_getset));
46481 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, h_getset);
46482 } else {
46483 duk_tval *tv_val;
46484 tv_val = &p_val[n].v;
46485 DUK_TVAL_DECREF_NORZ(thr, tv_val);
46486 }
46487 }
46488
46489 p_tv = DUK_HOBJECT_A_GET_BASE(thr->heap, h);
46490 n = DUK_HOBJECT_GET_ASIZE(h);
46491 while (n-- > 0) {
46492 duk_tval *tv_val;
46493 tv_val = p_tv + n;
46494 DUK_TVAL_DECREF_NORZ(thr, tv_val);
46495 }
46496
46497 /* hash part is a 'weak reference' and does not contribute */
46498
46499 {
46500 duk_hobject *h_proto;
46501 h_proto = (duk_hobject *) DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
46502 DUK_ASSERT(h_proto == NULL || DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_proto));
46503 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, h_proto);
46504 }
46505
46506 /* XXX: rearrange bits to allow a switch case to be used here? */
46507 /* XXX: add a fast path for objects (and arrays)? */
46508
46509 /* DUK_HOBJECT_IS_ARRAY(h): needs no special handling now as there are
46510 * no extra fields in need of decref.
46511 */
46512 if (DUK_HOBJECT_IS_COMPFUNC(h)) {
46513 duk_hcompfunc *f = (duk_hcompfunc *) h;
46514 duk_tval *tv, *tv_end;
46515 duk_hobject **funcs, **funcs_end;
46516
46517 if (DUK_HCOMPFUNC_GET_DATA(thr->heap, f) != NULL) {
46518 tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, f);
46519 tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, f);
46520 while (tv < tv_end) {
46521 DUK_TVAL_DECREF_NORZ(thr, tv);
46522 tv++;
46523 }
46524
46525 funcs = DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, f);
46526 funcs_end = DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, f);
46527 while (funcs < funcs_end) {
46528 duk_hobject *h_func;
46529 h_func = *funcs;
46530 DUK_ASSERT(DUK_HEAPHDR_IS_OBJECT((duk_heaphdr *) h_func));
46531 DUK_HCOMPFUNC_DECREF_NORZ(thr, (duk_hcompfunc *) h_func);
46532 funcs++;
46533 }
46534 } else {
46535 /* May happen in some out-of-memory corner cases. */
46536 DUK_D(DUK_DPRINT("duk_hcompfunc 'data' is NULL, skipping decref"));
46537 }
46538
46539 DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_heaphdr *) DUK_HCOMPFUNC_GET_LEXENV(thr->heap, f));
46540 DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_heaphdr *) DUK_HCOMPFUNC_GET_VARENV(thr->heap, f));
46541 DUK_HEAPHDR_DECREF_ALLOWNULL(thr, (duk_hbuffer *) DUK_HCOMPFUNC_GET_DATA(thr->heap, f));
46542 } else if (DUK_HOBJECT_IS_NATFUNC(h)) {
46543 duk_hnatfunc *f = (duk_hnatfunc *) h;
46544 DUK_UNREF(f);
46545 /* nothing to finalize */
46546#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
46547 } else if (DUK_HOBJECT_IS_BUFOBJ(h)) {
46548 duk_hbufobj *b = (duk_hbufobj *) h;
46549 DUK_HBUFFER_DECREF_NORZ_ALLOWNULL(thr, (duk_hbuffer *) b->buf);
46550 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) b->buf_prop);
46551#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
46552 } else if (DUK_HOBJECT_IS_THREAD(h)) {
46553 duk_hthread *t = (duk_hthread *) h;
46554 duk_tval *tv;
46555
46556 tv = t->valstack;
46557 while (tv < t->valstack_top) {
46558 DUK_TVAL_DECREF_NORZ(thr, tv);
46559 tv++;
46560 }
46561
46562 for (i = 0; i < (duk_uint_fast32_t) t->callstack_top; i++) {
46563 duk_activation *act = t->callstack + i;
46564 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) DUK_ACT_GET_FUNC(act));
46565 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) act->var_env);
46566 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) act->lex_env);
46567#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
46568 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) act->prev_caller);
46569#endif
46570 }
46571
46572#if 0 /* nothing now */
46573 for (i = 0; i < (duk_uint_fast32_t) t->catchstack_top; i++) {
46574 duk_catcher *cat = t->catchstack + i;
46575 }
46576#endif
46577
46578 for (i = 0; i < DUK_NUM_BUILTINS; i++) {
46579 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, (duk_hobject *) t->builtins[i]);
46580 }
46581
46582 DUK_HTHREAD_DECREF_NORZ_ALLOWNULL(thr, (duk_hthread *) t->resumer);
46583 }
46584}
46585
46586DUK_INTERNAL void duk_heaphdr_refcount_finalize(duk_hthread *thr, duk_heaphdr *hdr) {
46587 DUK_ASSERT(hdr);
46588
46589 if (DUK_HEAPHDR_GET_TYPE(hdr) == DUK_HTYPE_OBJECT) {
46590 duk__refcount_finalize_hobject(thr, (duk_hobject *) hdr);
46591 }
46592 /* DUK_HTYPE_BUFFER: nothing to finalize */
46593 /* DUK_HTYPE_STRING: nothing to finalize */
46594}
46595
46596#if defined(DUK_USE_FINALIZER_SUPPORT)
46597#if defined(DUK_USE_REFZERO_FINALIZER_TORTURE)
46598DUK_LOCAL duk_ret_t duk__refcount_fake_finalizer(duk_context *ctx) {
46599 DUK_UNREF(ctx);
46600 DUK_D(DUK_DPRINT("fake refcount torture finalizer executed"));
46601#if 0
46602 DUK_DD(DUK_DDPRINT("fake torture finalizer for: %!T", duk_get_tval(ctx, 0)));
46603#endif
46604 /* Require a lot of stack to force a value stack grow/shrink. */
46605 duk_require_stack(ctx, 100000);
46606
46607 /* XXX: do something to force a callstack grow/shrink, perhaps
46608 * just a manual forced resize?
46609 */
46610 return 0;
46611}
46612
46613DUK_LOCAL void duk__refcount_run_torture_finalizer(duk_hthread *thr, duk_hobject *obj) {
46614 duk_context *ctx;
46615 duk_int_t rc;
46616
46617 DUK_ASSERT(thr != NULL);
46618 DUK_ASSERT(obj != NULL);
46619 ctx = (duk_context *) thr;
46620
46621 /* Avoid fake finalization for the duk__refcount_fake_finalizer function
46622 * itself, otherwise we're in infinite recursion.
46623 */
46624 if (DUK_HOBJECT_HAS_NATFUNC(obj)) {
46625 if (((duk_hnatfunc *) obj)->func == duk__refcount_fake_finalizer) {
46626 DUK_DD(DUK_DDPRINT("avoid fake torture finalizer for duk__refcount_fake_finalizer itself"));
46627 return;
46628 }
46629 }
46630 /* Avoid fake finalization when callstack limit has been reached.
46631 * Otherwise a callstack limit error will be created, then refzero'ed,
46632 * and we're in an infinite loop.
46633 */
46634 if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit ||
46635 thr->callstack_size + 2 * DUK_CALLSTACK_GROW_STEP >= thr->callstack_max /*approximate*/) {
46636 DUK_D(DUK_DPRINT("call recursion depth reached, avoid fake torture finalizer"));
46637 return;
46638 }
46639
46640 /* Run fake finalizer. Avoid creating new refzero queue entries
46641 * so that we are not forced into a forever loop.
46642 */
46643 duk_push_c_function(ctx, duk__refcount_fake_finalizer, 1 /*nargs*/);
46644 duk_push_hobject(ctx, obj);
46645 rc = duk_pcall(ctx, 1);
46646 DUK_UNREF(rc); /* ignored */
46647 duk_pop(ctx);
46648}
46649#endif /* DUK_USE_REFZERO_FINALIZER_TORTURE */
46650#endif /* DUK_USE_FINALIZER_SUPPORT */
46651
46652/*
46653 * Refcount memory freeing loop.
46654 *
46655 * Frees objects in the refzero_pending list until the list becomes
46656 * empty. When an object is freed, its references get decref'd and
46657 * may cause further objects to be queued for freeing.
46658 *
46659 * This could be expanded to allow incremental freeing: just bail out
46660 * early and resume at a future alloc/decref/refzero.
46661 */
46662
46663DUK_INTERNAL void duk_refzero_free_pending(duk_hthread *thr) {
46664 duk_heaphdr *h1, *h2;
46665 duk_heap *heap;
46666 duk_int_t count = 0;
46667
46668 DUK_ASSERT(thr != NULL);
46669 DUK_ASSERT(thr->heap != NULL);
46670 heap = thr->heap;
46671 DUK_ASSERT(heap != NULL);
46672
46673 /*
46674 * Detect recursive invocation
46675 */
46676
46677 if (DUK_HEAP_HAS_REFZERO_FREE_RUNNING(heap)) {
46678 DUK_DDD(DUK_DDDPRINT("refzero free running, skip run"));
46679 return;
46680 }
46681
46682 /*
46683 * Churn refzero_list until empty
46684 */
46685
46686 DUK_HEAP_SET_REFZERO_FREE_RUNNING(heap);
46687 while (heap->refzero_list) {
46688 duk_hobject *obj;
46689#if defined(DUK_USE_FINALIZER_SUPPORT)
46690 duk_bool_t rescued = 0;
46691#endif /* DUK_USE_FINALIZER_SUPPORT */
46692
46693 /*
46694 * Pick an object from the head (don't remove yet).
46695 */
46696
46697 h1 = heap->refzero_list;
46698 obj = (duk_hobject *) h1;
46699 DUK_DD(DUK_DDPRINT("refzero processing %p: %!O", (void *) h1, (duk_heaphdr *) h1));
46700 DUK_ASSERT(DUK_HEAPHDR_GET_PREV(heap, h1) == NULL);
46701 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(h1) == DUK_HTYPE_OBJECT); /* currently, always the case */
46702
46703#if defined(DUK_USE_FINALIZER_SUPPORT)
46704#if defined(DUK_USE_REFZERO_FINALIZER_TORTURE)
46705 /* Torture option to shake out finalizer side effect issues:
46706 * make a bogus function call for every finalizable object,
46707 * essentially simulating the case where everything has a
46708 * finalizer.
46709 */
46710 DUK_DD(DUK_DDPRINT("refzero torture enabled, fake finalizer"));
46711 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h1) == 0);
46712 DUK_HEAPHDR_PREINC_REFCOUNT(h1); /* bump refcount to prevent refzero during finalizer processing */
46713 duk__refcount_run_torture_finalizer(thr, obj); /* must never longjmp */
46714 DUK_HEAPHDR_PREDEC_REFCOUNT(h1); /* remove artificial bump */
46715 DUK_ASSERT_DISABLE(h1->h_refcount >= 0); /* refcount is unsigned, so always true */
46716#endif /* DUK_USE_REFZERO_FINALIZER_TORTURE */
46717#endif /* DUK_USE_FINALIZER_SUPPORT */
46718
46719 /*
46720 * Finalizer check.
46721 *
46722 * Note: running a finalizer may have arbitrary side effects, e.g.
46723 * queue more objects on refzero_list (tail), or even trigger a
46724 * mark-and-sweep.
46725 *
46726 * Note: quick reject check should match vast majority of
46727 * objects and must be safe (not throw any errors, ever).
46728 *
46729 * An object may have FINALIZED here if it was finalized by mark-and-sweep
46730 * on a previous run and refcount then decreased to zero. We won't run the
46731 * finalizer again here.
46732 *
46733 * A finalizer is looked up from the object and up its prototype chain
46734 * (which allows inherited finalizers).
46735 */
46736
46737#if defined(DUK_USE_FINALIZER_SUPPORT)
46738 if (duk_hobject_hasprop_raw(thr, obj, DUK_HTHREAD_STRING_INT_FINALIZER(thr))) {
46739 DUK_DDD(DUK_DDDPRINT("object has a finalizer, run it"));
46740
46741 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h1) == 0);
46742 DUK_HEAPHDR_PREINC_REFCOUNT(h1); /* bump refcount to prevent refzero during finalizer processing */
46743
46744 duk_hobject_run_finalizer(thr, obj); /* must never longjmp */
46745 DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(h1)); /* duk_hobject_run_finalizer() sets */
46746
46747 DUK_HEAPHDR_PREDEC_REFCOUNT(h1); /* remove artificial bump */
46748 DUK_ASSERT_DISABLE(h1->h_refcount >= 0); /* refcount is unsigned, so always true */
46749
46750 if (DUK_HEAPHDR_GET_REFCOUNT(h1) != 0) {
46751 DUK_DDD(DUK_DDDPRINT("-> object refcount after finalization non-zero, object will be rescued"));
46752 rescued = 1;
46753 } else {
46754 DUK_DDD(DUK_DDDPRINT("-> object refcount still zero after finalization, object will be freed"));
46755 }
46756 }
46757#endif /* DUK_USE_FINALIZER_SUPPORT */
46758
46759 /* Refzero head is still the same. This is the case even if finalizer
46760 * inserted more refzero objects; they are inserted to the tail.
46761 */
46762 DUK_ASSERT(h1 == heap->refzero_list);
46763
46764 /*
46765 * Remove the object from the refzero list. This cannot be done
46766 * before a possible finalizer has been executed; the finalizer
46767 * may trigger a mark-and-sweep, and mark-and-sweep must be able
46768 * to traverse a complete refzero_list.
46769 */
46770
46771 h2 = DUK_HEAPHDR_GET_NEXT(heap, h1);
46772 if (h2) {
46773 DUK_HEAPHDR_SET_PREV(heap, h2, NULL); /* not strictly necessary */
46774 heap->refzero_list = h2;
46775 } else {
46776 heap->refzero_list = NULL;
46777 heap->refzero_list_tail = NULL;
46778 }
46779
46780 /*
46781 * Rescue or free.
46782 */
46783
46784#if defined(DUK_USE_FINALIZER_SUPPORT)
46785 if (rescued) {
46786 /* yes -> move back to heap allocated */
46787 DUK_DD(DUK_DDPRINT("object rescued during refcount finalization: %p", (void *) h1));
46788 DUK_ASSERT(!DUK_HEAPHDR_HAS_FINALIZABLE(h1));
46789 DUK_ASSERT(DUK_HEAPHDR_HAS_FINALIZED(h1));
46790 DUK_HEAPHDR_CLEAR_FINALIZED(h1);
46791 h2 = heap->heap_allocated;
46792 DUK_HEAPHDR_SET_PREV(heap, h1, NULL);
46793 if (h2) {
46794 DUK_HEAPHDR_SET_PREV(heap, h2, h1);
46795 }
46796 DUK_HEAPHDR_SET_NEXT(heap, h1, h2);
46797 DUK_ASSERT_HEAPHDR_LINKS(heap, h1);
46798 DUK_ASSERT_HEAPHDR_LINKS(heap, h2);
46799 heap->heap_allocated = h1;
46800 } else
46801#endif /* DUK_USE_FINALIZER_SUPPORT */
46802 {
46803 /* no -> decref members, then free */
46804 duk__refcount_finalize_hobject(thr, obj);
46805 DUK_ASSERT(DUK_HEAPHDR_GET_TYPE(h1) == DUK_HTYPE_OBJECT); /* currently, always the case */
46806 duk_free_hobject(heap, (duk_hobject *) h1);
46807 }
46808
46809 count++;
46810 }
46811 DUK_HEAP_CLEAR_REFZERO_FREE_RUNNING(heap);
46812
46813 DUK_DDD(DUK_DDDPRINT("refzero processed %ld objects", (long) count));
46814
46815 /*
46816 * Once the whole refzero cascade has been freed, check for
46817 * a voluntary mark-and-sweep.
46818 */
46819
46820#if defined(DUK_USE_VOLUNTARY_GC)
46821 /* 'count' is more or less comparable to normal trigger counter update
46822 * which happens in memory block (re)allocation.
46823 */
46824 heap->mark_and_sweep_trigger_counter -= count;
46825 if (heap->mark_and_sweep_trigger_counter <= 0) {
46826 duk_bool_t rc;
46827 duk_small_uint_t flags = 0; /* not emergency */
46828 DUK_D(DUK_DPRINT("refcount triggering mark-and-sweep"));
46829 rc = duk_heap_mark_and_sweep(heap, flags);
46830 DUK_UNREF(rc);
46831 DUK_D(DUK_DPRINT("refcount triggered mark-and-sweep => rc %ld", (long) rc));
46832 }
46833#endif /* DUK_USE_VOLUNTARY_GC */
46834}
46835
46836/*
46837 * Incref and decref functions.
46838 *
46839 * Decref may trigger immediate refzero handling, which may free and finalize
46840 * an arbitrary number of objects.
46841 *
46842 * Refzero handling is skipped entirely if (1) mark-and-sweep is running or
46843 * (2) execution is paused in the debugger. The objects are left in the heap,
46844 * and will be freed by mark-and-sweep or eventual heap destruction.
46845 *
46846 * This is necessary during mark-and-sweep because refcounts are also updated
46847 * during the sweep phase (otherwise objects referenced by a swept object
46848 * would have incorrect refcounts) which then calls here. This could be
46849 * avoided by using separate decref macros in mark-and-sweep; however,
46850 * mark-and-sweep also calls finalizers which would use the ordinary decref
46851 * macros anyway.
46852 *
46853 * The DUK__RZ_SUPPRESS_CHECK() must be enabled also when mark-and-sweep
46854 * support has been disabled: the flag is also used in heap destruction when
46855 * running finalizers for remaining objects, and the flag prevents objects
46856 * from being moved around in heap linked lists.
46857 */
46858
46859/* The suppress condition is important to performance. The flags being tested
46860 * are in the same duk_heap field so a single TEST instruction (on x86) tests
46861 * for them.
46862 */
46863#if defined(DUK_USE_DEBUGGER_SUPPORT)
46864#define DUK__RZ_SUPPRESS_COND() \
46865 (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap) || DUK_HEAP_IS_PAUSED(heap))
46866#else
46867#define DUK__RZ_SUPPRESS_COND() \
46868 (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap))
46869#endif
46870#define DUK__RZ_SUPPRESS_CHECK() do { \
46871 if (DUK_UNLIKELY(DUK__RZ_SUPPRESS_COND())) { \
46872 DUK_DDD(DUK_DDDPRINT("refzero handling suppressed when mark-and-sweep running, object: %p", (void *) h)); \
46873 return; \
46874 } \
46875 } while (0)
46876
46877#define DUK__RZ_STRING() do { \
46878 duk_heap_strcache_string_remove(thr->heap, (duk_hstring *) h); \
46879 duk_heap_string_remove(heap, (duk_hstring *) h); \
46880 duk_free_hstring(heap, (duk_hstring *) h); \
46881 } while (0)
46882#define DUK__RZ_BUFFER() do { \
46883 duk_heap_remove_any_from_heap_allocated(heap, (duk_heaphdr *) h); \
46884 duk_free_hbuffer(heap, (duk_hbuffer *) h); \
46885 } while (0)
46886#define DUK__RZ_OBJECT() do { \
46887 duk_heap_remove_any_from_heap_allocated(heap, (duk_heaphdr *) h); \
46888 duk__queue_refzero(heap, (duk_heaphdr *) h); \
46889 if (!skip_free_pending) { \
46890 duk_refzero_free_pending(thr); \
46891 } \
46892 } while (0)
46893#if defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
46894#define DUK__RZ_INLINE DUK_ALWAYS_INLINE
46895#else
46896#define DUK__RZ_INLINE /*nop*/
46897#endif
46898
46899DUK_LOCAL DUK__RZ_INLINE void duk__hstring_refzero_helper(duk_hthread *thr, duk_hstring *h) {
46900 duk_heap *heap;
46901
46902 DUK_ASSERT(thr != NULL);
46903 DUK_ASSERT(h != NULL);
46904 heap = thr->heap;
46905
46906 DUK__RZ_SUPPRESS_CHECK();
46907 DUK__RZ_STRING();
46908}
46909
46910DUK_LOCAL DUK__RZ_INLINE void duk__hbuffer_refzero_helper(duk_hthread *thr, duk_hbuffer *h) {
46911 duk_heap *heap;
46912
46913 DUK_ASSERT(thr != NULL);
46914 DUK_ASSERT(h != NULL);
46915 heap = thr->heap;
46916
46917 DUK__RZ_SUPPRESS_CHECK();
46918 DUK__RZ_BUFFER();
46919}
46920
46921DUK_LOCAL DUK__RZ_INLINE void duk__hobject_refzero_helper(duk_hthread *thr, duk_hobject *h, duk_bool_t skip_free_pending) {
46922 duk_heap *heap;
46923
46924 DUK_ASSERT(thr != NULL);
46925 DUK_ASSERT(h != NULL);
46926 heap = thr->heap;
46927
46928 DUK__RZ_SUPPRESS_CHECK();
46929 DUK__RZ_OBJECT();
46930}
46931
46932DUK_LOCAL DUK__RZ_INLINE void duk__heaphdr_refzero_helper(duk_hthread *thr, duk_heaphdr *h, duk_bool_t skip_free_pending) {
46933 duk_heap *heap;
46934 duk_small_uint_t htype;
46935
46936 DUK_ASSERT(thr != NULL);
46937 DUK_ASSERT(h != NULL);
46938 heap = thr->heap;
46939
46940 htype = (duk_small_uint_t) DUK_HEAPHDR_GET_TYPE(h);
46941 DUK__RZ_SUPPRESS_CHECK();
46942
46943 switch (htype) {
46944 case DUK_HTYPE_STRING:
46945 /* Strings have no internal references but do have "weak"
46946 * references in the string cache. Also note that strings
46947 * are not on the heap_allocated list like other heap
46948 * elements.
46949 */
46950
46951 DUK__RZ_STRING();
46952 break;
46953
46954 case DUK_HTYPE_OBJECT:
46955 /* Objects have internal references. Must finalize through
46956 * the "refzero" work list.
46957 */
46958
46959 DUK__RZ_OBJECT();
46960 break;
46961
46962 case DUK_HTYPE_BUFFER:
46963 /* Buffers have no internal references. However, a dynamic
46964 * buffer has a separate allocation for the buffer. This is
46965 * freed by duk_heap_free_heaphdr_raw().
46966 */
46967
46968 DUK__RZ_BUFFER();
46969 break;
46970
46971 default:
46972 DUK_D(DUK_DPRINT("invalid heap type in decref: %ld", (long) DUK_HEAPHDR_GET_TYPE(h)));
46973 DUK_UNREACHABLE();
46974 }
46975}
46976
46977DUK_INTERNAL void duk_heaphdr_refzero(duk_hthread *thr, duk_heaphdr *h) {
46978 duk__heaphdr_refzero_helper(thr, h, 0 /*skip_free_pending*/);
46979}
46980
46981DUK_INTERNAL void duk_heaphdr_refzero_norz(duk_hthread *thr, duk_heaphdr *h) {
46982 duk__heaphdr_refzero_helper(thr, h, 1 /*skip_free_pending*/);
46983}
46984
46985DUK_INTERNAL void duk_hstring_refzero(duk_hthread *thr, duk_hstring *h) {
46986 duk__hstring_refzero_helper(thr, h);
46987}
46988
46989DUK_INTERNAL void duk_hbuffer_refzero(duk_hthread *thr, duk_hbuffer *h) {
46990 duk__hbuffer_refzero_helper(thr, h);
46991}
46992
46993DUK_INTERNAL void duk_hobject_refzero(duk_hthread *thr, duk_hobject *h) {
46994 duk__hobject_refzero_helper(thr, h, 0 /*skip_free_pending*/);
46995}
46996
46997DUK_INTERNAL void duk_hobject_refzero_norz(duk_hthread *thr, duk_hobject *h) {
46998 duk__hobject_refzero_helper(thr, h, 1 /*skip_free_pending*/);
46999}
47000
47001#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
47002DUK_INTERNAL void duk_tval_incref(duk_tval *tv) {
47003 DUK_ASSERT(tv != NULL);
47004
47005 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) {
47006 duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
47007 DUK_ASSERT(h != NULL);
47008 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
47009 DUK_ASSERT_DISABLE(h->h_refcount >= 0);
47010 DUK_HEAPHDR_PREINC_REFCOUNT(h);
47011 }
47012}
47013
47014DUK_INTERNAL void duk_tval_decref(duk_hthread *thr, duk_tval *tv) {
47015 DUK_ASSERT(thr != NULL);
47016 DUK_ASSERT(tv != NULL);
47017
47018 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) {
47019 duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
47020 DUK_ASSERT(h != NULL);
47021 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
47022 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) >= 1);
47023#if 0
47024 if (DUK_HEAPHDR_PREDEC_REFCOUNT(h) != 0) {
47025 return;
47026 }
47027 duk_heaphdr_refzero(thr, h);
47028#else
47029 duk_heaphdr_decref(thr, h);
47030#endif
47031 }
47032}
47033
47034DUK_INTERNAL void duk_tval_decref_norz(duk_hthread *thr, duk_tval *tv) {
47035 DUK_ASSERT(thr != NULL);
47036 DUK_ASSERT(tv != NULL);
47037
47038 if (DUK_TVAL_NEEDS_REFCOUNT_UPDATE(tv)) {
47039 duk_heaphdr *h = DUK_TVAL_GET_HEAPHDR(tv);
47040 DUK_ASSERT(h != NULL);
47041 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
47042 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT(h) >= 1);
47043#if 0
47044 if (DUK_HEAPHDR_PREDEC_REFCOUNT(h) != 0) {
47045 return;
47046 }
47047 duk_heaphdr_refzero_norz(thr, h);
47048#else
47049 duk_heaphdr_decref(thr, h);
47050#endif
47051 }
47052}
47053#endif /* !DUK_USE_FAST_REFCOUNT_DEFAULT */
47054
47055#define DUK__DECREF_ASSERTS() do { \
47056 DUK_ASSERT(thr != NULL); \
47057 DUK_ASSERT(thr->heap != NULL); \
47058 DUK_ASSERT(h != NULL); \
47059 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID((duk_heaphdr *) h)); \
47060 DUK_ASSERT(DUK_HEAPHDR_GET_REFCOUNT((duk_heaphdr *) h) >= 1); \
47061 } while (0)
47062#if defined(DUK_USE_ROM_OBJECTS)
47063#define DUK__DECREF_SHARED() do { \
47064 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) h)) { \
47065 return; \
47066 } \
47067 if (DUK_HEAPHDR_PREDEC_REFCOUNT((duk_heaphdr *) h) != 0) { \
47068 return; \
47069 } \
47070 } while (0)
47071#else
47072#define DUK__DECREF_SHARED() do { \
47073 if (DUK_HEAPHDR_PREDEC_REFCOUNT((duk_heaphdr *) h) != 0) { \
47074 return; \
47075 } \
47076 } while (0)
47077#endif
47078
47079#if !defined(DUK_USE_FAST_REFCOUNT_DEFAULT)
47080/* This will in practice be inlined because it's just an INC instructions
47081 * and a bit test + INC when ROM objects are enabled.
47082 */
47083DUK_INTERNAL void duk_heaphdr_incref(duk_heaphdr *h) {
47084 DUK_ASSERT(h != NULL);
47085 DUK_ASSERT(DUK_HEAPHDR_HTYPE_VALID(h));
47086 DUK_ASSERT_DISABLE(DUK_HEAPHDR_GET_REFCOUNT(h) >= 0);
47087
47088 DUK_HEAPHDR_PREINC_REFCOUNT(h);
47089}
47090
47091DUK_INTERNAL void duk_heaphdr_decref(duk_hthread *thr, duk_heaphdr *h) {
47092 DUK__DECREF_ASSERTS();
47093 DUK__DECREF_SHARED();
47094 duk_heaphdr_refzero(thr, h);
47095}
47096DUK_INTERNAL void duk_heaphdr_decref_norz(duk_hthread *thr, duk_heaphdr *h) {
47097 DUK__DECREF_ASSERTS();
47098 DUK__DECREF_SHARED();
47099 duk_heaphdr_refzero_norz(thr, h);
47100}
47101#endif /* !DUK_USE_FAST_REFCOUNT_DEFAULT */
47102
47103#if 0 /* Not needed. */
47104DUK_INTERNAL void duk_hstring_decref(duk_hthread *thr, duk_hstring *h) {
47105 DUK__DECREF_ASSERTS();
47106 DUK__DECREF_SHARED();
47107 duk_hstring_refzero(thr, h);
47108}
47109DUK_INTERNAL void duk_hstring_decref_norz(duk_hthread *thr, duk_hstring *h) {
47110 DUK__DECREF_ASSERTS();
47111 DUK__DECREF_SHARED();
47112 duk_hstring_refzero_norz(thr, h);
47113}
47114DUK_INTERNAL void duk_hbuffer_decref(duk_hthread *thr, duk_hbuffer *h) {
47115 DUK__DECREF_ASSERTS();
47116 DUK__DECREF_SHARED();
47117 duk_hbuffer_refzero(thr, h);
47118}
47119DUK_INTERNAL void duk_hbuffer_decref_norz(duk_hthread *thr, duk_hbuffer *h) {
47120 DUK__DECREF_ASSERTS();
47121 DUK__DECREF_SHARED();
47122 duk_hbuffer_refzero_norz(thr, h);
47123}
47124DUK_INTERNAL void duk_hobject_decref(duk_hthread *thr, duk_hobject *h) {
47125 DUK__DECREF_ASSERTS();
47126 DUK__DECREF_SHARED();
47127 duk_hobject_refzero(thr, h);
47128}
47129DUK_INTERNAL void duk_hobject_decref_norz(duk_hthread *thr, duk_hobject *h) {
47130 DUK__DECREF_ASSERTS();
47131 DUK__DECREF_SHARED();
47132 duk_hobject_refzero_norz(thr, h);
47133}
47134#endif
47135
47136#else /* DUK_USE_REFERENCE_COUNTING */
47137
47138/* no refcounting */
47139
47140#endif /* DUK_USE_REFERENCE_COUNTING */
47141
47142/* automatic undefs */
47143#undef DUK__DECREF_ASSERTS
47144#undef DUK__DECREF_SHARED
47145#undef DUK__RZ_BUFFER
47146#undef DUK__RZ_INLINE
47147#undef DUK__RZ_OBJECT
47148#undef DUK__RZ_STRING
47149#undef DUK__RZ_SUPPRESS_CHECK
47150#undef DUK__RZ_SUPPRESS_COND
47151/*
47152 * String cache.
47153 *
47154 * Provides a cache to optimize indexed string lookups. The cache keeps
47155 * track of (byte offset, char offset) states for a fixed number of strings.
47156 * Otherwise we'd need to scan from either end of the string, as we store
47157 * strings in (extended) UTF-8.
47158 */
47159
47160/* #include duk_internal.h -> already included */
47161
47162/*
47163 * Delete references to given hstring from the heap string cache.
47164 *
47165 * String cache references are 'weak': they are not counted towards
47166 * reference counts, nor serve as roots for mark-and-sweep. When an
47167 * object is about to be freed, such references need to be removed.
47168 */
47169
47170DUK_INTERNAL void duk_heap_strcache_string_remove(duk_heap *heap, duk_hstring *h) {
47171 duk_small_int_t i;
47172 for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
47173 duk_strcache *c = heap->strcache + i;
47174 if (c->h == h) {
47175 DUK_DD(DUK_DDPRINT("deleting weak strcache reference to hstring %p from heap %p",
47176 (void *) h, (void *) heap));
47177 c->h = NULL;
47178
47179 /* XXX: the string shouldn't appear twice, but we now loop to the
47180 * end anyway; if fixed, add a looping assertion to ensure there
47181 * is no duplicate.
47182 */
47183 }
47184 }
47185}
47186
47187/*
47188 * String scanning helpers
47189 *
47190 * All bytes other than UTF-8 continuation bytes ([0x80,0xbf]) are
47191 * considered to contribute a character. This must match how string
47192 * character length is computed.
47193 */
47194
47195DUK_LOCAL const duk_uint8_t *duk__scan_forwards(const duk_uint8_t *p, const duk_uint8_t *q, duk_uint_fast32_t n) {
47196 while (n > 0) {
47197 for (;;) {
47198 p++;
47199 if (p >= q) {
47200 return NULL;
47201 }
47202 if ((*p & 0xc0) != 0x80) {
47203 break;
47204 }
47205 }
47206 n--;
47207 }
47208 return p;
47209}
47210
47211DUK_LOCAL const duk_uint8_t *duk__scan_backwards(const duk_uint8_t *p, const duk_uint8_t *q, duk_uint_fast32_t n) {
47212 while (n > 0) {
47213 for (;;) {
47214 p--;
47215 if (p < q) {
47216 return NULL;
47217 }
47218 if ((*p & 0xc0) != 0x80) {
47219 break;
47220 }
47221 }
47222 n--;
47223 }
47224 return p;
47225}
47226
47227/*
47228 * Convert char offset to byte offset
47229 *
47230 * Avoid using the string cache if possible: for ASCII strings byte and
47231 * char offsets are equal and for short strings direct scanning may be
47232 * better than using the string cache (which may evict a more important
47233 * entry).
47234 *
47235 * Typing now assumes 32-bit string byte/char offsets (duk_uint_fast32_t).
47236 * Better typing might be to use duk_size_t.
47237 */
47238
47239DUK_INTERNAL duk_uint_fast32_t duk_heap_strcache_offset_char2byte(duk_hthread *thr, duk_hstring *h, duk_uint_fast32_t char_offset) {
47240 duk_heap *heap;
47241 duk_strcache *sce;
47242 duk_uint_fast32_t byte_offset;
47243 duk_small_int_t i;
47244 duk_bool_t use_cache;
47245 duk_uint_fast32_t dist_start, dist_end, dist_sce;
47246 const duk_uint8_t *p_start;
47247 const duk_uint8_t *p_end;
47248 const duk_uint8_t *p_found;
47249
47250 if (char_offset > DUK_HSTRING_GET_CHARLEN(h)) {
47251 goto error;
47252 }
47253
47254 /*
47255 * For ASCII strings, the answer is simple.
47256 */
47257
47258 if (DUK_HSTRING_IS_ASCII(h)) {
47259 /* clen == blen -> pure ascii */
47260 return char_offset;
47261 }
47262
47263 /*
47264 * For non-ASCII strings, we need to scan forwards or backwards
47265 * from some starting point. The starting point may be the start
47266 * or end of the string, or some cached midpoint in the string
47267 * cache.
47268 *
47269 * For "short" strings we simply scan without checking or updating
47270 * the cache. For longer strings we check and update the cache as
47271 * necessary, inserting a new cache entry if none exists.
47272 */
47273
47274 DUK_DDD(DUK_DDDPRINT("non-ascii string %p, char_offset=%ld, clen=%ld, blen=%ld",
47275 (void *) h, (long) char_offset,
47276 (long) DUK_HSTRING_GET_CHARLEN(h),
47277 (long) DUK_HSTRING_GET_BYTELEN(h)));
47278
47279 heap = thr->heap;
47280 sce = NULL;
47281 use_cache = (DUK_HSTRING_GET_CHARLEN(h) > DUK_HEAP_STRINGCACHE_NOCACHE_LIMIT);
47282
47283 if (use_cache) {
47284#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
47285 DUK_DDD(DUK_DDDPRINT("stringcache before char2byte (using cache):"));
47286 for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
47287 duk_strcache *c = heap->strcache + i;
47288 DUK_DDD(DUK_DDDPRINT(" [%ld] -> h=%p, cidx=%ld, bidx=%ld",
47289 (long) i, (void *) c->h, (long) c->cidx, (long) c->bidx));
47290 }
47291#endif
47292
47293 for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
47294 duk_strcache *c = heap->strcache + i;
47295
47296 if (c->h == h) {
47297 sce = c;
47298 break;
47299 }
47300 }
47301 }
47302
47303 /*
47304 * Scan from shortest distance:
47305 * - start of string
47306 * - end of string
47307 * - cache entry (if exists)
47308 */
47309
47310 DUK_ASSERT(DUK_HSTRING_GET_CHARLEN(h) >= char_offset);
47311 dist_start = char_offset;
47312 dist_end = DUK_HSTRING_GET_CHARLEN(h) - char_offset;
47313 dist_sce = 0; DUK_UNREF(dist_sce); /* initialize for debug prints, needed if sce==NULL */
47314
47315 p_start = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
47316 p_end = (const duk_uint8_t *) (p_start + DUK_HSTRING_GET_BYTELEN(h));
47317 p_found = NULL;
47318
47319 if (sce) {
47320 if (char_offset >= sce->cidx) {
47321 dist_sce = char_offset - sce->cidx;
47322 if ((dist_sce <= dist_start) && (dist_sce <= dist_end)) {
47323 DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
47324 "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
47325 "scan forwards from sce",
47326 (long) use_cache, (void *) (sce ? sce->h : NULL),
47327 (sce ? (long) sce->cidx : (long) -1),
47328 (sce ? (long) sce->bidx : (long) -1),
47329 (long) dist_start, (long) dist_end, (long) dist_sce));
47330
47331 p_found = duk__scan_forwards(p_start + sce->bidx,
47332 p_end,
47333 dist_sce);
47334 goto scan_done;
47335 }
47336 } else {
47337 dist_sce = sce->cidx - char_offset;
47338 if ((dist_sce <= dist_start) && (dist_sce <= dist_end)) {
47339 DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
47340 "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
47341 "scan backwards from sce",
47342 (long) use_cache, (void *) (sce ? sce->h : NULL),
47343 (sce ? (long) sce->cidx : (long) -1),
47344 (sce ? (long) sce->bidx : (long) -1),
47345 (long) dist_start, (long) dist_end, (long) dist_sce));
47346
47347 p_found = duk__scan_backwards(p_start + sce->bidx,
47348 p_start,
47349 dist_sce);
47350 goto scan_done;
47351 }
47352 }
47353 }
47354
47355 /* no sce, or sce scan not best */
47356
47357 if (dist_start <= dist_end) {
47358 DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
47359 "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
47360 "scan forwards from string start",
47361 (long) use_cache, (void *) (sce ? sce->h : NULL),
47362 (sce ? (long) sce->cidx : (long) -1),
47363 (sce ? (long) sce->bidx : (long) -1),
47364 (long) dist_start, (long) dist_end, (long) dist_sce));
47365
47366 p_found = duk__scan_forwards(p_start,
47367 p_end,
47368 dist_start);
47369 } else {
47370 DUK_DDD(DUK_DDDPRINT("non-ascii string, use_cache=%ld, sce=%p:%ld:%ld, "
47371 "dist_start=%ld, dist_end=%ld, dist_sce=%ld => "
47372 "scan backwards from string end",
47373 (long) use_cache, (void *) (sce ? sce->h : NULL),
47374 (sce ? (long) sce->cidx : (long) -1),
47375 (sce ? (long) sce->bidx : (long) -1),
47376 (long) dist_start, (long) dist_end, (long) dist_sce));
47377
47378 p_found = duk__scan_backwards(p_end,
47379 p_start,
47380 dist_end);
47381 }
47382
47383 scan_done:
47384
47385 if (!p_found) {
47386 /* Scan error: this shouldn't normally happen; it could happen if
47387 * string is not valid UTF-8 data, and clen/blen are not consistent
47388 * with the scanning algorithm.
47389 */
47390 goto error;
47391 }
47392
47393 DUK_ASSERT(p_found >= p_start);
47394 DUK_ASSERT(p_found <= p_end); /* may be equal */
47395 byte_offset = (duk_uint32_t) (p_found - p_start);
47396
47397 DUK_DDD(DUK_DDDPRINT("-> string %p, cidx %ld -> bidx %ld",
47398 (void *) h, (long) char_offset, (long) byte_offset));
47399
47400 /*
47401 * Update cache entry (allocating if necessary), and move the
47402 * cache entry to the first place (in an "LRU" policy).
47403 */
47404
47405 if (use_cache) {
47406 /* update entry, allocating if necessary */
47407 if (!sce) {
47408 sce = heap->strcache + DUK_HEAP_STRCACHE_SIZE - 1; /* take last entry */
47409 sce->h = h;
47410 }
47411 DUK_ASSERT(sce != NULL);
47412 sce->bidx = (duk_uint32_t) (p_found - p_start);
47413 sce->cidx = (duk_uint32_t) char_offset;
47414
47415 /* LRU: move our entry to first */
47416 if (sce > &heap->strcache[0]) {
47417 /*
47418 * A C
47419 * B A
47420 * C <- sce ==> B
47421 * D D
47422 */
47423 duk_strcache tmp;
47424
47425 tmp = *sce;
47426 DUK_MEMMOVE((void *) (&heap->strcache[1]),
47427 (const void *) (&heap->strcache[0]),
47428 (size_t) (((char *) sce) - ((char *) &heap->strcache[0])));
47429 heap->strcache[0] = tmp;
47430
47431 /* 'sce' points to the wrong entry here, but is no longer used */
47432 }
47433#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
47434 DUK_DDD(DUK_DDDPRINT("stringcache after char2byte (using cache):"));
47435 for (i = 0; i < DUK_HEAP_STRCACHE_SIZE; i++) {
47436 duk_strcache *c = heap->strcache + i;
47437 DUK_DDD(DUK_DDDPRINT(" [%ld] -> h=%p, cidx=%ld, bidx=%ld",
47438 (long) i, (void *) c->h, (long) c->cidx, (long) c->bidx));
47439 }
47440#endif
47441 }
47442
47443 return byte_offset;
47444
47445 error:
47446 DUK_ERROR_INTERNAL(thr);
47447 return 0;
47448}
47449/*
47450 * Heap stringtable handling, string interning.
47451 */
47452
47453/* #include duk_internal.h -> already included */
47454
47455#if defined(DUK_USE_STRTAB_PROBE)
47456#define DUK__HASH_INITIAL(hash,h_size) DUK_STRTAB_HASH_INITIAL((hash),(h_size))
47457#define DUK__HASH_PROBE_STEP(hash) DUK_STRTAB_HASH_PROBE_STEP((hash))
47458#define DUK__DELETED_MARKER(heap) DUK_STRTAB_DELETED_MARKER((heap))
47459#endif
47460
47461#define DUK__PREVENT_MS_SIDE_EFFECTS(heap) do { \
47462 (heap)->mark_and_sweep_base_flags |= \
47463 DUK_MS_FLAG_NO_STRINGTABLE_RESIZE | /* avoid recursive string table call */ \
47464 DUK_MS_FLAG_NO_FINALIZERS | /* avoid pressure to add/remove strings, invalidation of call data argument, etc. */ \
47465 DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid array abandoning which interns strings */ \
47466 } while (0)
47467
47468/*
47469 * Create a hstring and insert into the heap. The created object
47470 * is directly garbage collectable with reference count zero.
47471 *
47472 * The caller must place the interned string into the stringtable
47473 * immediately (without chance of a longjmp); otherwise the string
47474 * is lost.
47475 */
47476
47477DUK_LOCAL
47478duk_hstring *duk__alloc_init_hstring(duk_heap *heap,
47479 const duk_uint8_t *str,
47480 duk_uint32_t blen,
47481 duk_uint32_t strhash,
47482 const duk_uint8_t *extdata) {
47483 duk_hstring *res = NULL;
47484 duk_uint8_t *data;
47485 duk_size_t alloc_size;
47486#if !defined(DUK_USE_HSTRING_ARRIDX)
47487 duk_uarridx_t dummy;
47488#endif
47489 duk_uint32_t clen;
47490
47491#if defined(DUK_USE_STRLEN16)
47492 /* If blen <= 0xffffUL, clen is also guaranteed to be <= 0xffffUL. */
47493 if (blen > 0xffffUL) {
47494 DUK_D(DUK_DPRINT("16-bit string blen/clen active and blen over 16 bits, reject intern"));
47495 return NULL;
47496 }
47497#endif
47498
47499 if (extdata) {
47500 alloc_size = (duk_size_t) sizeof(duk_hstring_external);
47501 res = (duk_hstring *) DUK_ALLOC(heap, alloc_size);
47502 if (!res) {
47503 goto alloc_error;
47504 }
47505 DUK_MEMZERO(res, sizeof(duk_hstring_external));
47506#if defined(DUK_USE_EXPLICIT_NULL_INIT)
47507 DUK_HEAPHDR_STRING_INIT_NULLS(&res->hdr);
47508#endif
47509 DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, DUK_HSTRING_FLAG_EXTDATA);
47510
47511 ((duk_hstring_external *) res)->extdata = extdata;
47512 } else {
47513 /* NUL terminate for convenient C access */
47514 alloc_size = (duk_size_t) (sizeof(duk_hstring) + blen + 1);
47515 res = (duk_hstring *) DUK_ALLOC(heap, alloc_size);
47516 if (!res) {
47517 goto alloc_error;
47518 }
47519 DUK_MEMZERO(res, sizeof(duk_hstring));
47520#if defined(DUK_USE_EXPLICIT_NULL_INIT)
47521 DUK_HEAPHDR_STRING_INIT_NULLS(&res->hdr);
47522#endif
47523 DUK_HEAPHDR_SET_TYPE_AND_FLAGS(&res->hdr, DUK_HTYPE_STRING, 0);
47524
47525 data = (duk_uint8_t *) (res + 1);
47526 DUK_MEMCPY(data, str, blen);
47527 data[blen] = (duk_uint8_t) 0;
47528 }
47529
47530 DUK_ASSERT(!DUK_HSTRING_HAS_ARRIDX(res));
47531#if defined(DUK_USE_HSTRING_ARRIDX)
47532 if (duk_js_to_arrayindex_raw_string(str, blen, &res->arridx)) {
47533#else
47534 if (duk_js_to_arrayindex_raw_string(str, blen, &dummy)) {
47535#endif
47536 DUK_HSTRING_SET_ARRIDX(res);
47537 }
47538
47539 /* All strings beginning with specific (invalid UTF-8) byte prefixes
47540 * are treated as symbols.
47541 */
47542 DUK_ASSERT(!DUK_HSTRING_HAS_SYMBOL(res));
47543 DUK_ASSERT(!DUK_HSTRING_HAS_HIDDEN(res));
47544 if (blen > 0) {
47545 if (str[0] == 0xffU) {
47546 DUK_HSTRING_SET_SYMBOL(res);
47547 DUK_HSTRING_SET_HIDDEN(res);
47548 } else if ((str[0] & 0xc0U) == 0x80U) {
47549 DUK_HSTRING_SET_SYMBOL(res);
47550 }
47551 }
47552
47553 DUK_HSTRING_SET_HASH(res, strhash);
47554 DUK_HSTRING_SET_BYTELEN(res, blen);
47555
47556 clen = (duk_uint32_t) duk_unicode_unvalidated_utf8_length(str, (duk_size_t) blen);
47557 DUK_ASSERT(clen <= blen);
47558#if defined(DUK_USE_HSTRING_CLEN)
47559 DUK_HSTRING_SET_CHARLEN(res, clen);
47560#endif
47561
47562 /* Using an explicit 'ASCII' flag has larger footprint (one call site
47563 * only) but is quite useful for the case when there's no explicit
47564 * 'clen' in duk_hstring.
47565 */
47566 DUK_ASSERT(!DUK_HSTRING_HAS_ASCII(res));
47567 if (clen == blen) {
47568 DUK_HSTRING_SET_ASCII(res);
47569 }
47570
47571 DUK_DDD(DUK_DDDPRINT("interned string, hash=0x%08lx, blen=%ld, clen=%ld, has_arridx=%ld, has_extdata=%ld",
47572 (unsigned long) DUK_HSTRING_GET_HASH(res),
47573 (long) DUK_HSTRING_GET_BYTELEN(res),
47574 (long) DUK_HSTRING_GET_CHARLEN(res),
47575 (long) (DUK_HSTRING_HAS_ARRIDX(res) ? 1 : 0),
47576 (long) (DUK_HSTRING_HAS_EXTDATA(res) ? 1 : 0)));
47577
47578 return res;
47579
47580 alloc_error:
47581 DUK_FREE(heap, res);
47582 return NULL;
47583}
47584
47585/*
47586 * String table algorithm: fixed size string table with array chaining
47587 *
47588 * The top level string table has a fixed size, with each slot holding
47589 * either NULL, string pointer, or pointer to a separately allocated
47590 * string pointer list.
47591 *
47592 * This is good for low memory environments using a pool allocator: the
47593 * top level allocation has a fixed size and the pointer lists have quite
47594 * small allocation size, which further matches the typical pool sizes
47595 * needed by objects, strings, property tables, etc.
47596 */
47597
47598#if defined(DUK_USE_STRTAB_CHAIN)
47599
47600#if defined(DUK_USE_HEAPPTR16)
47601DUK_LOCAL duk_bool_t duk__insert_hstring_chain(duk_heap *heap, duk_hstring *h) {
47602 duk_small_uint_t slotidx;
47604 duk_uint16_t *lst;
47605 duk_uint16_t *new_lst;
47606 duk_size_t i, n;
47607 duk_uint16_t null16 = heap->heapptr_null16;
47608 duk_uint16_t h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
47609
47610 DUK_ASSERT(heap != NULL);
47611 DUK_ASSERT(h != NULL);
47612
47613 slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE;
47614 DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
47615
47616 e = heap->strtable + slotidx;
47617 if (e->listlen == 0) {
47618 if (e->u.str16 == null16) {
47619 e->u.str16 = h16;
47620 } else {
47621 /* Now two entries in the same slot, alloc list */
47622 lst = (duk_uint16_t *) DUK_ALLOC(heap, sizeof(duk_uint16_t) * 2);
47623 if (lst == NULL) {
47624 return 1; /* fail */
47625 }
47626 lst[0] = e->u.str16;
47627 lst[1] = h16;
47628 e->u.strlist16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) lst);
47629 e->listlen = 2;
47630 }
47631 } else {
47632 DUK_ASSERT(e->u.strlist16 != null16);
47633 lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
47634 DUK_ASSERT(lst != NULL);
47635 for (i = 0, n = e->listlen; i < n; i++) {
47636 if (lst[i] == null16) {
47637 lst[i] = h16;
47638 return 0;
47639 }
47640 }
47641
47642 if (e->listlen + 1 == 0) {
47643 /* Overflow, relevant mainly when listlen is 16 bits. */
47644 return 1; /* fail */
47645 }
47646
47647 new_lst = (duk_uint16_t *) DUK_REALLOC(heap, lst, sizeof(duk_uint16_t) * (e->listlen + 1));
47648 if (new_lst == NULL) {
47649 return 1; /* fail */
47650 }
47651 new_lst[e->listlen++] = h16;
47652 e->u.strlist16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) new_lst);
47653 }
47654 return 0;
47655}
47656#else /* DUK_USE_HEAPPTR16 */
47657DUK_LOCAL duk_bool_t duk__insert_hstring_chain(duk_heap *heap, duk_hstring *h) {
47658 duk_small_uint_t slotidx;
47660 duk_hstring **lst;
47661 duk_hstring **new_lst;
47662 duk_size_t i, n;
47663
47664 DUK_ASSERT(heap != NULL);
47665 DUK_ASSERT(h != NULL);
47666
47667 slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE;
47668 DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
47669
47670 e = heap->strtable + slotidx;
47671 if (e->listlen == 0) {
47672 if (e->u.str == NULL) {
47673 e->u.str = h;
47674 } else {
47675 /* Now two entries in the same slot, alloc list */
47676 lst = (duk_hstring **) DUK_ALLOC(heap, sizeof(duk_hstring *) * 2);
47677 if (lst == NULL) {
47678 return 1; /* fail */
47679 }
47680 lst[0] = e->u.str;
47681 lst[1] = h;
47682 e->u.strlist = lst;
47683 e->listlen = 2;
47684 }
47685 } else {
47686 DUK_ASSERT(e->u.strlist != NULL);
47687 lst = e->u.strlist;
47688 for (i = 0, n = e->listlen; i < n; i++) {
47689 if (lst[i] == NULL) {
47690 lst[i] = h;
47691 return 0;
47692 }
47693 }
47694
47695 if (e->listlen + 1 == 0) {
47696 /* Overflow, relevant mainly when listlen is 16 bits. */
47697 return 1; /* fail */
47698 }
47699
47700 new_lst = (duk_hstring **) DUK_REALLOC(heap, e->u.strlist, sizeof(duk_hstring *) * (e->listlen + 1));
47701 if (new_lst == NULL) {
47702 return 1; /* fail */
47703 }
47704 new_lst[e->listlen++] = h;
47705 e->u.strlist = new_lst;
47706 }
47707 return 0;
47708}
47709#endif /* DUK_USE_HEAPPTR16 */
47710
47711#if defined(DUK_USE_HEAPPTR16)
47712DUK_LOCAL duk_hstring *duk__find_matching_string_chain(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) {
47713 duk_small_uint_t slotidx;
47715 duk_uint16_t *lst;
47716 duk_size_t i, n;
47717 duk_uint16_t null16 = heap->heapptr_null16;
47718
47719 DUK_ASSERT(heap != NULL);
47720
47721 slotidx = strhash % DUK_STRTAB_CHAIN_SIZE;
47722 DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
47723
47724 e = heap->strtable + slotidx;
47725 if (e->listlen == 0) {
47726 if (e->u.str16 != null16) {
47727 duk_hstring *h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16);
47728 DUK_ASSERT(h != NULL);
47729 if (DUK_HSTRING_GET_BYTELEN(h) == blen &&
47730 DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) {
47731 return h;
47732 }
47733 }
47734 } else {
47735 DUK_ASSERT(e->u.strlist16 != null16);
47736 lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
47737 DUK_ASSERT(lst != NULL);
47738 for (i = 0, n = e->listlen; i < n; i++) {
47739 if (lst[i] != null16) {
47740 duk_hstring *h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[i]);
47741 DUK_ASSERT(h != NULL);
47742 if (DUK_HSTRING_GET_BYTELEN(h) == blen &&
47743 DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(h), (size_t) blen) == 0) {
47744 return h;
47745 }
47746 }
47747 }
47748 }
47749
47750 return NULL;
47751}
47752#else /* DUK_USE_HEAPPTR16 */
47753DUK_LOCAL duk_hstring *duk__find_matching_string_chain(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) {
47754 duk_small_uint_t slotidx;
47756 duk_hstring **lst;
47757 duk_size_t i, n;
47758
47759 DUK_ASSERT(heap != NULL);
47760
47761 slotidx = strhash % DUK_STRTAB_CHAIN_SIZE;
47762 DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
47763
47764 e = heap->strtable + slotidx;
47765 if (e->listlen == 0) {
47766 if (e->u.str != NULL &&
47767 DUK_HSTRING_GET_BYTELEN(e->u.str) == blen &&
47768 DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(e->u.str), (size_t) blen) == 0) {
47769 return e->u.str;
47770 }
47771 } else {
47772 DUK_ASSERT(e->u.strlist != NULL);
47773 lst = e->u.strlist;
47774 for (i = 0, n = e->listlen; i < n; i++) {
47775 if (lst[i] != NULL &&
47776 DUK_HSTRING_GET_BYTELEN(lst[i]) == blen &&
47777 DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(lst[i]), (size_t) blen) == 0) {
47778 return lst[i];
47779 }
47780 }
47781 }
47782
47783 return NULL;
47784}
47785#endif /* DUK_USE_HEAPPTR16 */
47786
47787#if defined(DUK_USE_HEAPPTR16)
47788DUK_LOCAL void duk__remove_matching_hstring_chain(duk_heap *heap, duk_hstring *h) {
47789 duk_small_uint_t slotidx;
47791 duk_uint16_t *lst;
47792 duk_size_t i, n;
47793 duk_uint16_t h16;
47794 duk_uint16_t null16 = heap->heapptr_null16;
47795
47796 DUK_ASSERT(heap != NULL);
47797 DUK_ASSERT(h != NULL);
47798
47799 slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE;
47800 DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
47801
47802 DUK_ASSERT(h != NULL);
47803 h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
47804
47805 e = heap->strtable + slotidx;
47806 if (e->listlen == 0) {
47807 if (e->u.str16 == h16) {
47808 e->u.str16 = null16;
47809 return;
47810 }
47811 } else {
47812 DUK_ASSERT(e->u.strlist16 != null16);
47813 lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
47814 DUK_ASSERT(lst != NULL);
47815 for (i = 0, n = e->listlen; i < n; i++) {
47816 if (lst[i] == h16) {
47817 lst[i] = null16;
47818 return;
47819 }
47820 }
47821 }
47822
47823 DUK_D(DUK_DPRINT("failed to find string that should be in stringtable"));
47824 DUK_UNREACHABLE();
47825 return;
47826}
47827#else /* DUK_USE_HEAPPTR16 */
47828DUK_LOCAL void duk__remove_matching_hstring_chain(duk_heap *heap, duk_hstring *h) {
47829 duk_small_uint_t slotidx;
47831 duk_hstring **lst;
47832 duk_size_t i, n;
47833
47834 DUK_ASSERT(heap != NULL);
47835 DUK_ASSERT(h != NULL);
47836
47837 slotidx = DUK_HSTRING_GET_HASH(h) % DUK_STRTAB_CHAIN_SIZE;
47838 DUK_ASSERT(slotidx < DUK_STRTAB_CHAIN_SIZE);
47839
47840 e = heap->strtable + slotidx;
47841 if (e->listlen == 0) {
47842 DUK_ASSERT(h != NULL);
47843 if (e->u.str == h) {
47844 e->u.str = NULL;
47845 return;
47846 }
47847 } else {
47848 DUK_ASSERT(e->u.strlist != NULL);
47849 lst = e->u.strlist;
47850 for (i = 0, n = e->listlen; i < n; i++) {
47851 DUK_ASSERT(h != NULL);
47852 if (lst[i] == h) {
47853 lst[i] = NULL;
47854 return;
47855 }
47856 }
47857 }
47858
47859 DUK_D(DUK_DPRINT("failed to find string that should be in stringtable"));
47860 DUK_UNREACHABLE();
47861 return;
47862}
47863#endif /* DUK_USE_HEAPPTR16 */
47864
47865#if defined(DUK_USE_DEBUG)
47866DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap) {
47868 duk_small_uint_t i;
47869 duk_size_t j, n, used;
47870#if defined(DUK_USE_HEAPPTR16)
47871 duk_uint16_t *lst;
47872 duk_uint16_t null16 = heap->heapptr_null16;
47873#else
47874 duk_hstring **lst;
47875#endif
47876
47877 DUK_ASSERT(heap != NULL);
47878
47879 for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
47880 e = heap->strtable + i;
47881
47882 if (e->listlen == 0) {
47883#if defined(DUK_USE_HEAPPTR16)
47884 DUK_DD(DUK_DDPRINT("[%03d] -> plain %d", (int) i, (int) (e->u.str16 != null16 ? 1 : 0)));
47885#else
47886 DUK_DD(DUK_DDPRINT("[%03d] -> plain %d", (int) i, (int) (e->u.str ? 1 : 0)));
47887#endif
47888 } else {
47889 used = 0;
47890#if defined(DUK_USE_HEAPPTR16)
47891 lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
47892#else
47893 lst = e->u.strlist;
47894#endif
47895 DUK_ASSERT(lst != NULL);
47896 for (j = 0, n = e->listlen; j < n; j++) {
47897#if defined(DUK_USE_HEAPPTR16)
47898 if (lst[j] != null16) {
47899#else
47900 if (lst[j] != NULL) {
47901#endif
47902 used++;
47903 }
47904 }
47905 DUK_DD(DUK_DDPRINT("[%03d] -> array %d/%d", (int) i, (int) used, (int) e->listlen));
47906 }
47907 }
47908}
47909#endif /* DUK_USE_DEBUG */
47910
47911#endif /* DUK_USE_STRTAB_CHAIN */
47912
47913/*
47914 * String table algorithm: closed hashing with a probe sequence
47915 *
47916 * This is the default algorithm and works fine for environments with
47917 * minimal memory constraints.
47918 */
47919
47920#if defined(DUK_USE_STRTAB_PROBE)
47921
47922/* Count actually used (non-NULL, non-DELETED) entries. */
47923DUK_LOCAL duk_int_t duk__count_used_probe(duk_heap *heap) {
47924 duk_int_t res = 0;
47925 duk_uint_fast32_t i, n;
47926#if defined(DUK_USE_HEAPPTR16)
47927 duk_uint16_t null16 = heap->heapptr_null16;
47928 duk_uint16_t deleted16 = heap->heapptr_deleted16;
47929#endif
47930
47931 n = (duk_uint_fast32_t) heap->st_size;
47932 for (i = 0; i < n; i++) {
47933#if defined(DUK_USE_HEAPPTR16)
47934 if (heap->strtable16[i] != null16 && heap->strtable16[i] != deleted16) {
47935#else
47936 if (heap->strtable[i] != NULL && heap->strtable[i] != DUK__DELETED_MARKER(heap)) {
47937#endif
47938 res++;
47939 }
47940 }
47941 return res;
47942}
47943
47944#if defined(DUK_USE_HEAPPTR16)
47945DUK_LOCAL void duk__insert_hstring_probe(duk_heap *heap, duk_uint16_t *entries16, duk_uint32_t size, duk_uint32_t *p_used, duk_hstring *h) {
47946#else
47947DUK_LOCAL void duk__insert_hstring_probe(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, duk_uint32_t *p_used, duk_hstring *h) {
47948#endif
47949 duk_uint32_t i;
47950 duk_uint32_t step;
47951#if defined(DUK_USE_HEAPPTR16)
47952 duk_uint16_t null16 = heap->heapptr_null16;
47953 duk_uint16_t deleted16 = heap->heapptr_deleted16;
47954#endif
47955
47956 DUK_ASSERT(size > 0);
47957
47958 i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(h), size);
47959 step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(h));
47960 for (;;) {
47961#if defined(DUK_USE_HEAPPTR16)
47962 duk_uint16_t e16 = entries16[i];
47963#else
47964 duk_hstring *e = entries[i];
47965#endif
47966
47967#if defined(DUK_USE_HEAPPTR16)
47968 /* XXX: could check for e16 == 0 because NULL is guaranteed to
47969 * encode to zero.
47970 */
47971 if (e16 == null16) {
47972#else
47973 if (e == NULL) {
47974#endif
47975 DUK_DDD(DUK_DDDPRINT("insert hit (null): %ld", (long) i));
47976#if defined(DUK_USE_HEAPPTR16)
47977 entries16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
47978#else
47979 entries[i] = h;
47980#endif
47981 (*p_used)++;
47982 break;
47983#if defined(DUK_USE_HEAPPTR16)
47984 } else if (e16 == deleted16) {
47985#else
47986 } else if (e == DUK__DELETED_MARKER(heap)) {
47987#endif
47988 /* st_used remains the same, DELETED is counted as used */
47989 DUK_DDD(DUK_DDDPRINT("insert hit (deleted): %ld", (long) i));
47990#if defined(DUK_USE_HEAPPTR16)
47991 entries16[i] = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
47992#else
47993 entries[i] = h;
47994#endif
47995 break;
47996 }
47997 DUK_DDD(DUK_DDDPRINT("insert miss: %ld", (long) i));
47998 i = (i + step) % size;
47999
48000 /* looping should never happen */
48001 DUK_ASSERT(i != DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(h), size));
48002 }
48003}
48004
48005#if defined(DUK_USE_HEAPPTR16)
48006DUK_LOCAL duk_hstring *duk__find_matching_string_probe(duk_heap *heap, duk_uint16_t *entries16, duk_uint32_t size, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) {
48007#else
48008DUK_LOCAL duk_hstring *duk__find_matching_string_probe(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) {
48009#endif
48010 duk_uint32_t i;
48011 duk_uint32_t step;
48012
48013 DUK_ASSERT(size > 0);
48014
48015 i = DUK__HASH_INITIAL(strhash, size);
48016 step = DUK__HASH_PROBE_STEP(strhash);
48017 for (;;) {
48018 duk_hstring *e;
48019#if defined(DUK_USE_HEAPPTR16)
48020 e = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, entries16[i]);
48021#else
48022 e = entries[i];
48023#endif
48024
48025 if (!e) {
48026 return NULL;
48027 }
48028 if (e != DUK__DELETED_MARKER(heap) && DUK_HSTRING_GET_BYTELEN(e) == blen) {
48029 if (DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(e), (size_t) blen) == 0) {
48030 DUK_DDD(DUK_DDDPRINT("find matching hit: %ld (step %ld, size %ld)",
48031 (long) i, (long) step, (long) size));
48032 return e;
48033 }
48034 }
48035 DUK_DDD(DUK_DDDPRINT("find matching miss: %ld (step %ld, size %ld)",
48036 (long) i, (long) step, (long) size));
48037 i = (i + step) % size;
48038
48039 /* looping should never happen */
48040 DUK_ASSERT(i != DUK__HASH_INITIAL(strhash, size));
48041 }
48042 DUK_UNREACHABLE();
48043}
48044
48045#if defined(DUK_USE_HEAPPTR16)
48046DUK_LOCAL void duk__remove_matching_hstring_probe(duk_heap *heap, duk_uint16_t *entries16, duk_uint32_t size, duk_hstring *h) {
48047#else
48048DUK_LOCAL void duk__remove_matching_hstring_probe(duk_heap *heap, duk_hstring **entries, duk_uint32_t size, duk_hstring *h) {
48049#endif
48050 duk_uint32_t i;
48051 duk_uint32_t step;
48052 duk_uint32_t hash;
48053#if defined(DUK_USE_HEAPPTR16)
48054 duk_uint16_t null16 = heap->heapptr_null16;
48055 duk_uint16_t h16 = DUK_USE_HEAPPTR_ENC16(heap->heap_udata, (void *) h);
48056#endif
48057
48058 DUK_ASSERT(size > 0);
48059
48060 hash = DUK_HSTRING_GET_HASH(h);
48061 i = DUK__HASH_INITIAL(hash, size);
48062 step = DUK__HASH_PROBE_STEP(hash);
48063 for (;;) {
48064#if defined(DUK_USE_HEAPPTR16)
48065 duk_uint16_t e16 = entries16[i];
48066#else
48067 duk_hstring *e = entries[i];
48068#endif
48069
48070#if defined(DUK_USE_HEAPPTR16)
48071 if (e16 == null16) {
48072#else
48073 if (!e) {
48074#endif
48075 DUK_UNREACHABLE();
48076 break;
48077 }
48078#if defined(DUK_USE_HEAPPTR16)
48079 if (e16 == h16) {
48080#else
48081 if (e == h) {
48082#endif
48083 /* st_used remains the same, DELETED is counted as used */
48084 DUK_DDD(DUK_DDDPRINT("free matching hit: %ld", (long) i));
48085#if defined(DUK_USE_HEAPPTR16)
48086 entries16[i] = heap->heapptr_deleted16;
48087#else
48088 entries[i] = DUK__DELETED_MARKER(heap);
48089#endif
48090 break;
48091 }
48092
48093 DUK_DDD(DUK_DDDPRINT("free matching miss: %ld", (long) i));
48094 i = (i + step) % size;
48095
48096 /* looping should never happen */
48097 DUK_ASSERT(i != DUK__HASH_INITIAL(hash, size));
48098 }
48099}
48100
48101DUK_LOCAL duk_bool_t duk__resize_strtab_raw_probe(duk_heap *heap, duk_uint32_t new_size) {
48102#if defined(DUK_USE_DEBUG)
48103 duk_uint32_t old_used = heap->st_used;
48104#endif
48105 duk_uint32_t old_size = heap->st_size;
48106#if defined(DUK_USE_HEAPPTR16)
48107 duk_uint16_t *old_entries = heap->strtable16;
48108 duk_uint16_t *new_entries = NULL;
48109#else
48110 duk_hstring **old_entries = heap->strtable;
48111 duk_hstring **new_entries = NULL;
48112#endif
48113 duk_uint32_t new_used = 0;
48114 duk_uint32_t i;
48115
48116#if defined(DUK_USE_DEBUG)
48117 DUK_UNREF(old_used); /* unused with some debug level combinations */
48118#endif
48119
48120#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
48121 DUK_DDD(DUK_DDDPRINT("attempt to resize stringtable: %ld entries, %ld bytes, %ld used, %ld%% load -> %ld entries, %ld bytes, %ld used, %ld%% load",
48122 (long) old_size, (long) (sizeof(duk_hstring *) * old_size), (long) old_used,
48123 (long) (((double) old_used) / ((double) old_size) * 100.0),
48124 (long) new_size, (long) (sizeof(duk_hstring *) * new_size), (long) duk__count_used_probe(heap),
48125 (long) (((double) duk__count_used_probe(heap)) / ((double) new_size) * 100.0)));
48126#endif
48127
48128 DUK_ASSERT(new_size > (duk_uint32_t) duk__count_used_probe(heap)); /* required for rehash to succeed, equality not that useful */
48129 DUK_ASSERT(old_entries);
48130
48131 /*
48132 * The attempt to allocate may cause a GC. Such a GC must not attempt to resize
48133 * the stringtable (though it can be swept); finalizer execution and object
48134 * compaction must also be postponed to avoid the pressure to add strings to the
48135 * string table. Call site must prevent these.
48136 */
48137
48138 DUK_ASSERT(heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE);
48139 DUK_ASSERT(heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_FINALIZERS);
48140 DUK_ASSERT(heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_OBJECT_COMPACTION);
48141
48142#if defined(DUK_USE_HEAPPTR16)
48143 new_entries = (duk_uint16_t *) DUK_ALLOC(heap, sizeof(duk_uint16_t) * new_size);
48144#else
48145 new_entries = (duk_hstring **) DUK_ALLOC(heap, sizeof(duk_hstring *) * new_size);
48146#endif
48147
48148 if (!new_entries) {
48149 goto resize_error;
48150 }
48151
48152#if defined(DUK_USE_EXPLICIT_NULL_INIT)
48153 for (i = 0; i < new_size; i++) {
48154#if defined(DUK_USE_HEAPPTR16)
48155 new_entries[i] = heap->heapptr_null16;
48156#else
48157 new_entries[i] = NULL;
48158#endif
48159 }
48160#else
48161#if defined(DUK_USE_HEAPPTR16)
48162 /* Relies on NULL encoding to zero. */
48163 DUK_MEMZERO(new_entries, sizeof(duk_uint16_t) * new_size);
48164#else
48165 DUK_MEMZERO(new_entries, sizeof(duk_hstring *) * new_size);
48166#endif
48167#endif
48168
48169 /* Because new_size > duk__count_used_probe(heap), guaranteed to work */
48170 for (i = 0; i < old_size; i++) {
48171 duk_hstring *e;
48172
48173#if defined(DUK_USE_HEAPPTR16)
48174 e = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, old_entries[i]);
48175#else
48176 e = old_entries[i];
48177#endif
48178 if (e == NULL || e == DUK__DELETED_MARKER(heap)) {
48179 continue;
48180 }
48181 /* checking for DUK__DELETED_MARKER is not necessary here, but helper does it now */
48182 duk__insert_hstring_probe(heap, new_entries, new_size, &new_used, e);
48183 }
48184
48185#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
48186 DUK_DD(DUK_DDPRINT("resized stringtable: %ld entries, %ld bytes, %ld used, %ld%% load -> %ld entries, %ld bytes, %ld used, %ld%% load",
48187 (long) old_size, (long) (sizeof(duk_hstring *) * old_size), (long) old_used,
48188 (long) (((double) old_used) / ((double) old_size) * 100.0),
48189 (long) new_size, (long) (sizeof(duk_hstring *) * new_size), (long) new_used,
48190 (long) (((double) new_used) / ((double) new_size) * 100.0)));
48191#endif
48192
48193#if defined(DUK_USE_HEAPPTR16)
48194 DUK_FREE(heap, heap->strtable16);
48195 heap->strtable16 = new_entries;
48196#else
48197 DUK_FREE(heap, heap->strtable);
48198 heap->strtable = new_entries;
48199#endif
48200 heap->st_size = new_size;
48201 heap->st_used = new_used; /* may be less, since DELETED entries are NULLed by rehash */
48202
48203 return 0; /* OK */
48204
48205 resize_error:
48206 DUK_FREE(heap, new_entries);
48207 return 1; /* FAIL */
48208}
48209
48210DUK_LOCAL duk_bool_t duk__resize_strtab_probe(duk_heap *heap) {
48211 duk_uint32_t new_size;
48212 duk_bool_t ret;
48213
48214 new_size = (duk_uint32_t) duk__count_used_probe(heap);
48215 if (new_size >= 0x80000000UL) {
48216 new_size = DUK_STRTAB_HIGHEST_32BIT_PRIME;
48217 } else {
48218 new_size = duk_util_get_hash_prime(DUK_STRTAB_GROW_ST_SIZE(new_size));
48219 new_size = duk_util_get_hash_prime(new_size);
48220 }
48221 DUK_ASSERT(new_size > 0);
48222
48223 /* rehash even if old and new sizes are the same to get rid of
48224 * DELETED entries.
48225 */
48226
48227 ret = duk__resize_strtab_raw_probe(heap, new_size);
48228
48229 return ret;
48230}
48231
48232DUK_LOCAL duk_bool_t duk__recheck_strtab_size_probe(duk_heap *heap, duk_uint32_t new_used) {
48233 duk_uint32_t new_free;
48234 duk_uint32_t tmp1;
48235 duk_uint32_t tmp2;
48236
48237 DUK_ASSERT(new_used <= heap->st_size); /* grow by at most one */
48238 new_free = heap->st_size - new_used; /* unsigned intentionally */
48239
48240 /* new_free / size <= 1 / DIV <=> new_free <= size / DIV */
48241 /* new_used / size <= 1 / DIV <=> new_used <= size / DIV */
48242
48243 tmp1 = heap->st_size / DUK_STRTAB_MIN_FREE_DIVISOR;
48244 tmp2 = heap->st_size / DUK_STRTAB_MIN_USED_DIVISOR;
48245
48246 if (new_free <= tmp1 || new_used <= tmp2) {
48247 /* load factor too low or high, count actually used entries and resize */
48248 return duk__resize_strtab_probe(heap);
48249 } else {
48250 return 0; /* OK */
48251 }
48252}
48253
48254#if defined(DUK_USE_DEBUG)
48255DUK_INTERNAL void duk_heap_dump_strtab(duk_heap *heap) {
48256 duk_uint32_t i;
48257 duk_hstring *h;
48258
48259 DUK_ASSERT(heap != NULL);
48260#if defined(DUK_USE_HEAPPTR16)
48261 DUK_ASSERT(heap->strtable16 != NULL);
48262#else
48263 DUK_ASSERT(heap->strtable != NULL);
48264#endif
48265 DUK_UNREF(h);
48266
48267 for (i = 0; i < heap->st_size; i++) {
48268#if defined(DUK_USE_HEAPPTR16)
48269 h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->strtable16[i]);
48270#else
48271 h = heap->strtable[i];
48272#endif
48273
48274 DUK_DD(DUK_DDPRINT("[%03d] -> %p", (int) i, (void *) h));
48275 }
48276}
48277#endif /* DUK_USE_DEBUG */
48278
48279#endif /* DUK_USE_STRTAB_PROBE */
48280
48281/*
48282 * Raw intern and lookup
48283 */
48284
48285DUK_LOCAL duk_hstring *duk__do_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t strhash) {
48286 duk_hstring *res;
48287 const duk_uint8_t *extdata;
48288 duk_small_uint_t prev_mark_and_sweep_base_flags;
48289
48290 /* Prevent any side effects on the string table and the caller provided
48291 * str/blen arguments while interning is in progress. For example, if
48292 * the caller provided str/blen from a dynamic buffer, a finalizer might
48293 * resize that dynamic buffer, invalidating the call arguments.
48294 */
48295 DUK_ASSERT((heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE) == 0);
48296 prev_mark_and_sweep_base_flags = heap->mark_and_sweep_base_flags;
48297 DUK__PREVENT_MS_SIDE_EFFECTS(heap);
48298
48299#if defined(DUK_USE_STRTAB_PROBE)
48300 if (duk__recheck_strtab_size_probe(heap, heap->st_used + 1)) {
48301 goto failed;
48302 }
48303#endif
48304
48305#if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_INTERN_CHECK)
48306 extdata = (const duk_uint8_t *) DUK_USE_EXTSTR_INTERN_CHECK(heap->heap_udata, (void *) DUK_LOSE_CONST(str), (duk_size_t) blen);
48307#else
48308 extdata = (const duk_uint8_t *) NULL;
48309#endif
48310 res = duk__alloc_init_hstring(heap, str, blen, strhash, extdata);
48311 if (!res) {
48312 goto failed;
48313 }
48314
48315#if defined(DUK_USE_STRTAB_CHAIN)
48316 if (duk__insert_hstring_chain(heap, res)) {
48317 /* failed */
48318 DUK_FREE(heap, res);
48319 goto failed;
48320 }
48321#elif defined(DUK_USE_STRTAB_PROBE)
48322 /* guaranteed to succeed */
48323 duk__insert_hstring_probe(heap,
48324#if defined(DUK_USE_HEAPPTR16)
48325 heap->strtable16,
48326#else
48327 heap->strtable,
48328#endif
48329 heap->st_size,
48330 &heap->st_used,
48331 res);
48332#else
48333#error internal error, invalid strtab options
48334#endif
48335
48336 /* Note: hstring is in heap but has refcount zero and is not strongly reachable.
48337 * Caller should increase refcount and make the hstring reachable before any
48338 * operations which require allocation (and possible gc).
48339 */
48340
48341 done:
48342 heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
48343 return res;
48344
48345 failed:
48346 res = NULL;
48347 goto done;
48348}
48349
48350DUK_LOCAL duk_hstring *duk__do_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen, duk_uint32_t *out_strhash) {
48351 duk_hstring *res;
48352
48353 DUK_ASSERT(out_strhash);
48354
48355 *out_strhash = duk_heap_hashstring(heap, str, (duk_size_t) blen);
48356
48357#if defined(DUK_USE_ROM_STRINGS)
48358 {
48359 duk_small_uint_t i;
48360 /* XXX: This is VERY inefficient now, and should be e.g. a
48361 * binary search or perfect hash, to be fixed.
48362 */
48363 for (i = 0; i < (duk_small_uint_t) (sizeof(duk_rom_strings) / sizeof(duk_hstring *)); i++) {
48364 duk_hstring *romstr;
48365 romstr = (duk_hstring *) DUK_LOSE_CONST(duk_rom_strings[i]);
48366 if (blen == DUK_HSTRING_GET_BYTELEN(romstr) &&
48367 DUK_MEMCMP((const void *) str, (const void *) DUK_HSTRING_GET_DATA(romstr), blen) == 0) {
48368 DUK_DD(DUK_DDPRINT("intern check: rom string: %!O, computed hash 0x%08lx, rom hash 0x%08lx",
48369 romstr, (unsigned long) *out_strhash, (unsigned long) DUK_HSTRING_GET_HASH(romstr)));
48370 DUK_ASSERT(*out_strhash == DUK_HSTRING_GET_HASH(romstr));
48371 *out_strhash = DUK_HSTRING_GET_HASH(romstr);
48372 return romstr;
48373 }
48374 }
48375 }
48376#endif /* DUK_USE_ROM_STRINGS */
48377
48378#if defined(DUK_USE_STRTAB_CHAIN)
48379 res = duk__find_matching_string_chain(heap, str, blen, *out_strhash);
48380#elif defined(DUK_USE_STRTAB_PROBE)
48381 res = duk__find_matching_string_probe(heap,
48382#if defined(DUK_USE_HEAPPTR16)
48383 heap->strtable16,
48384#else
48385 heap->strtable,
48386#endif
48387 heap->st_size,
48388 str,
48389 blen,
48390 *out_strhash);
48391#else
48392#error internal error, invalid strtab options
48393#endif
48394
48395 return res;
48396}
48397
48398/*
48399 * Exposed calls
48400 */
48401
48402#if 0 /*unused*/
48403DUK_INTERNAL duk_hstring *duk_heap_string_lookup(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen) {
48404 duk_uint32_t strhash; /* dummy */
48405 return duk__do_lookup(heap, str, blen, &strhash);
48406}
48407#endif
48408
48409DUK_INTERNAL duk_hstring *duk_heap_string_intern(duk_heap *heap, const duk_uint8_t *str, duk_uint32_t blen) {
48410 duk_hstring *res;
48411 duk_uint32_t strhash;
48412
48413 /* caller is responsible for ensuring this */
48414 DUK_ASSERT(blen <= DUK_HSTRING_MAX_BYTELEN);
48415
48416 res = duk__do_lookup(heap, str, blen, &strhash);
48417 if (res) {
48418 return res;
48419 }
48420
48421 res = duk__do_intern(heap, str, blen, strhash);
48422 return res; /* may be NULL */
48423}
48424
48425DUK_INTERNAL duk_hstring *duk_heap_string_intern_checked(duk_hthread *thr, const duk_uint8_t *str, duk_uint32_t blen) {
48426 duk_hstring *res = duk_heap_string_intern(thr->heap, str, blen);
48427 if (!res) {
48428 DUK_ERROR_ALLOC_FAILED(thr);
48429 }
48430 return res;
48431}
48432
48433#if 0 /*unused*/
48434DUK_INTERNAL duk_hstring *duk_heap_string_lookup_u32(duk_heap *heap, duk_uint32_t val) {
48435 char buf[DUK_STRTAB_U32_MAX_STRLEN+1];
48436 DUK_SNPRINTF(buf, sizeof(buf), "%lu", (unsigned long) val);
48437 buf[sizeof(buf) - 1] = (char) 0;
48438 DUK_ASSERT(DUK_STRLEN(buf) <= DUK_UINT32_MAX); /* formatted result limited */
48439 return duk_heap_string_lookup(heap, (const duk_uint8_t *) buf, (duk_uint32_t) DUK_STRLEN(buf));
48440}
48441#endif
48442
48443DUK_INTERNAL duk_hstring *duk_heap_string_intern_u32(duk_heap *heap, duk_uint32_t val) {
48444 char buf[DUK_STRTAB_U32_MAX_STRLEN+1];
48445 DUK_SNPRINTF(buf, sizeof(buf), "%lu", (unsigned long) val);
48446 buf[sizeof(buf) - 1] = (char) 0;
48447 DUK_ASSERT(DUK_STRLEN(buf) <= DUK_UINT32_MAX); /* formatted result limited */
48448 return duk_heap_string_intern(heap, (const duk_uint8_t *) buf, (duk_uint32_t) DUK_STRLEN(buf));
48449}
48450
48451DUK_INTERNAL duk_hstring *duk_heap_string_intern_u32_checked(duk_hthread *thr, duk_uint32_t val) {
48452 duk_hstring *res = duk_heap_string_intern_u32(thr->heap, val);
48453 if (!res) {
48454 DUK_ERROR_ALLOC_FAILED(thr);
48455 }
48456 return res;
48457}
48458
48459/* find and remove string from stringtable; caller must free the string itself */
48460#if defined(DUK_USE_REFERENCE_COUNTING)
48461DUK_INTERNAL void duk_heap_string_remove(duk_heap *heap, duk_hstring *h) {
48462 DUK_DDD(DUK_DDDPRINT("remove string from stringtable: %!O", (duk_heaphdr *) h));
48463
48464#if defined(DUK_USE_STRTAB_CHAIN)
48465 duk__remove_matching_hstring_chain(heap, h);
48466#elif defined(DUK_USE_STRTAB_PROBE)
48467 duk__remove_matching_hstring_probe(heap,
48468#if defined(DUK_USE_HEAPPTR16)
48469 heap->strtable16,
48470#else
48471 heap->strtable,
48472#endif
48473 heap->st_size,
48474 h);
48475#else
48476#error internal error, invalid strtab options
48477#endif
48478}
48479#endif
48480
48481#if defined(DUK_USE_MS_STRINGTABLE_RESIZE)
48482DUK_INTERNAL void duk_heap_force_strtab_resize(duk_heap *heap) {
48483 duk_small_uint_t prev_mark_and_sweep_base_flags;
48484 /* Force a resize so that DELETED entries are eliminated.
48485 * Another option would be duk__recheck_strtab_size_probe();
48486 * but since that happens on every intern anyway, this whole
48487 * check can now be disabled.
48488 */
48489
48490 DUK_ASSERT((heap->mark_and_sweep_base_flags & DUK_MS_FLAG_NO_STRINGTABLE_RESIZE) == 0);
48491 prev_mark_and_sweep_base_flags = heap->mark_and_sweep_base_flags;
48492 DUK__PREVENT_MS_SIDE_EFFECTS(heap);
48493
48494#if defined(DUK_USE_STRTAB_CHAIN)
48495 DUK_UNREF(heap);
48496#elif defined(DUK_USE_STRTAB_PROBE)
48497 (void) duk__resize_strtab_probe(heap);
48498#endif
48499
48500 heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
48501}
48502#endif
48503
48504#if defined(DUK_USE_STRTAB_CHAIN)
48505DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap) {
48506 /* Free strings in the stringtable and any allocations needed
48507 * by the stringtable itself.
48508 */
48509 duk_uint_fast32_t i, j;
48511#if defined(DUK_USE_HEAPPTR16)
48512 duk_uint16_t *lst;
48513 duk_uint16_t null16 = heap->heapptr_null16;
48514#else
48515 duk_hstring **lst;
48516#endif
48517 duk_hstring *h;
48518
48519 for (i = 0; i < DUK_STRTAB_CHAIN_SIZE; i++) {
48520 e = heap->strtable + i;
48521 if (e->listlen > 0) {
48522#if defined(DUK_USE_HEAPPTR16)
48523 lst = (duk_uint16_t *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.strlist16);
48524#else
48525 lst = e->u.strlist;
48526#endif
48527 DUK_ASSERT(lst != NULL);
48528
48529 for (j = 0; j < e->listlen; j++) {
48530#if defined(DUK_USE_HEAPPTR16)
48531 h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, lst[j]);
48532 lst[j] = null16;
48533#else
48534 h = lst[j];
48535 lst[j] = NULL;
48536#endif
48537 /* strings may have inner refs (extdata) in some cases */
48538 if (h != NULL) {
48539 duk_free_hstring(heap, h);
48540 }
48541 }
48542#if defined(DUK_USE_HEAPPTR16)
48543 e->u.strlist16 = null16;
48544#else
48545 e->u.strlist = NULL;
48546#endif
48547 DUK_FREE(heap, lst);
48548 } else {
48549#if defined(DUK_USE_HEAPPTR16)
48550 h = DUK_USE_HEAPPTR_DEC16(heap->heap_udata, e->u.str16);
48551 e->u.str16 = null16;
48552#else
48553 h = e->u.str;
48554 e->u.str = NULL;
48555#endif
48556 if (h != NULL) {
48557 duk_free_hstring(heap, h);
48558 }
48559 }
48560 e->listlen = 0;
48561 }
48562}
48563#endif /* DUK_USE_STRTAB_CHAIN */
48564
48565#if defined(DUK_USE_STRTAB_PROBE)
48566DUK_INTERNAL void duk_heap_free_strtab(duk_heap *heap) {
48567 duk_uint_fast32_t i;
48568 duk_hstring *h;
48569
48570#if defined(DUK_USE_HEAPPTR16)
48571 if (heap->strtable16) {
48572#else
48573 if (heap->strtable) {
48574#endif
48575 for (i = 0; i < (duk_uint_fast32_t) heap->st_size; i++) {
48576#if defined(DUK_USE_HEAPPTR16)
48577 h = (duk_hstring *) DUK_USE_HEAPPTR_DEC16(heap->heap_udata, heap->strtable16[i]);
48578#else
48579 h = heap->strtable[i];
48580#endif
48581 if (h == NULL || h == DUK_STRTAB_DELETED_MARKER(heap)) {
48582 continue;
48583 }
48584 DUK_ASSERT(h != NULL);
48585
48586 /* strings may have inner refs (extdata) in some cases */
48587 duk_free_hstring(heap, h);
48588#if 0 /* not strictly necessary */
48589 heap->strtable[i] = NULL;
48590#endif
48591 }
48592#if defined(DUK_USE_HEAPPTR16)
48593 DUK_FREE(heap, heap->strtable16);
48594#else
48595 DUK_FREE(heap, heap->strtable);
48596#endif
48597#if 0 /* not strictly necessary */
48598 heap->strtable = NULL;
48599#endif
48600 }
48601}
48602#endif /* DUK_USE_STRTAB_PROBE */
48603
48604/* automatic undefs */
48605#undef DUK__DELETED_MARKER
48606#undef DUK__HASH_INITIAL
48607#undef DUK__HASH_PROBE_STEP
48608#undef DUK__PREVENT_MS_SIDE_EFFECTS
48609/*
48610 * Hobject allocation.
48611 *
48612 * Provides primitive allocation functions for all object types (plain object,
48613 * compiled function, native function, thread). The object return is not yet
48614 * in "heap allocated" list and has a refcount of zero, so caller must careful.
48615 */
48616
48617/* #include duk_internal.h -> already included */
48618
48619DUK_LOCAL void duk__init_object_parts(duk_heap *heap, duk_hobject *obj, duk_uint_t hobject_flags) {
48620#if defined(DUK_USE_EXPLICIT_NULL_INIT)
48621 DUK_HOBJECT_SET_PROPS(heap, obj, NULL);
48622#endif
48623
48624 /* XXX: macro? sets both heaphdr and object flags */
48625 obj->hdr.h_flags = hobject_flags;
48626 DUK_HEAPHDR_SET_TYPE(&obj->hdr, DUK_HTYPE_OBJECT); /* also goes into flags */
48627
48628#if defined(DUK_USE_HEAPPTR16)
48629 /* Zero encoded pointer is required to match NULL */
48630 DUK_HEAPHDR_SET_NEXT(heap, &obj->hdr, NULL);
48631#if defined(DUK_USE_DOUBLE_LINKED_HEAP)
48632 DUK_HEAPHDR_SET_PREV(heap, &obj->hdr, NULL);
48633#endif
48634#endif
48635 DUK_ASSERT_HEAPHDR_LINKS(heap, &obj->hdr);
48636 DUK_HEAP_INSERT_INTO_HEAP_ALLOCATED(heap, &obj->hdr);
48637
48638 /*
48639 * obj->props is intentionally left as NULL, and duk_hobject_props.c must deal
48640 * with this properly. This is intentional: empty objects consume a minimum
48641 * amount of memory. Further, an initial allocation might fail and cause
48642 * 'obj' to "leak" (require a mark-and-sweep) since it is not reachable yet.
48643 */
48644}
48645
48646/*
48647 * Allocate an duk_hobject.
48648 *
48649 * The allocated object has no allocation for properties; the caller may
48650 * want to force a resize if a desired size is known.
48651 *
48652 * The allocated object has zero reference count and is not reachable.
48653 * The caller MUST make the object reachable and increase its reference
48654 * count before invoking any operation that might require memory allocation.
48655 */
48656
48657DUK_INTERNAL duk_hobject *duk_hobject_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
48658 duk_hobject *res;
48659
48660 DUK_ASSERT(heap != NULL);
48661
48662 /* different memory layout, alloc size, and init */
48663 DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_COMPFUNC) == 0);
48664 DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_NATFUNC) == 0);
48665 DUK_ASSERT((hobject_flags & DUK_HOBJECT_FLAG_THREAD) == 0);
48666
48667 res = (duk_hobject *) DUK_ALLOC(heap, sizeof(duk_hobject));
48668 if (!res) {
48669 return NULL;
48670 }
48671 DUK_MEMZERO(res, sizeof(duk_hobject));
48672
48673 duk__init_object_parts(heap, res, hobject_flags);
48674
48675 return res;
48676}
48677
48678DUK_INTERNAL duk_hcompfunc *duk_hcompfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
48679 duk_hcompfunc *res;
48680
48681 res = (duk_hcompfunc *) DUK_ALLOC(heap, sizeof(duk_hcompfunc));
48682 if (!res) {
48683 return NULL;
48684 }
48685 DUK_MEMZERO(res, sizeof(duk_hcompfunc));
48686
48687 duk__init_object_parts(heap, &res->obj, hobject_flags);
48688
48689#if defined(DUK_USE_EXPLICIT_NULL_INIT)
48690#if defined(DUK_USE_HEAPPTR16)
48691 /* NULL pointer is required to encode to zero, so memset is enough. */
48692#else
48693 res->data = NULL;
48694 res->funcs = NULL;
48695 res->bytecode = NULL;
48696#endif
48697 res->lex_env = NULL;
48698 res->var_env = NULL;
48699#endif
48700
48701 return res;
48702}
48703
48704DUK_INTERNAL duk_hnatfunc *duk_hnatfunc_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
48705 duk_hnatfunc *res;
48706
48707 res = (duk_hnatfunc *) DUK_ALLOC(heap, sizeof(duk_hnatfunc));
48708 if (!res) {
48709 return NULL;
48710 }
48711 DUK_MEMZERO(res, sizeof(duk_hnatfunc));
48712
48713 duk__init_object_parts(heap, &res->obj, hobject_flags);
48714
48715#if defined(DUK_USE_EXPLICIT_NULL_INIT)
48716 res->func = NULL;
48717#endif
48718
48719 return res;
48720}
48721
48722#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
48723DUK_INTERNAL duk_hbufobj *duk_hbufobj_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
48724 duk_hbufobj *res;
48725
48726 res = (duk_hbufobj *) DUK_ALLOC(heap, sizeof(duk_hbufobj));
48727 if (!res) {
48728 return NULL;
48729 }
48730 DUK_MEMZERO(res, sizeof(duk_hbufobj));
48731
48732 duk__init_object_parts(heap, &res->obj, hobject_flags);
48733
48734#if defined(DUK_USE_EXPLICIT_NULL_INIT)
48735 res->buf = NULL;
48736 res->buf_prop = NULL;
48737#endif
48738
48739 DUK_ASSERT_HBUFOBJ_VALID(res);
48740 return res;
48741}
48742#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
48743
48744/*
48745 * Allocate a new thread.
48746 *
48747 * Leaves the built-ins array uninitialized. The caller must either
48748 * initialize a new global context or share existing built-ins from
48749 * another thread.
48750 */
48751
48752DUK_INTERNAL duk_hthread *duk_hthread_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
48753 duk_hthread *res;
48754
48755 res = (duk_hthread *) DUK_ALLOC(heap, sizeof(duk_hthread));
48756 if (!res) {
48757 return NULL;
48758 }
48759 DUK_MEMZERO(res, sizeof(duk_hthread));
48760
48761 duk__init_object_parts(heap, &res->obj, hobject_flags);
48762
48763#if defined(DUK_USE_EXPLICIT_NULL_INIT)
48764 res->ptr_curr_pc = NULL;
48765 res->heap = NULL;
48766 res->valstack = NULL;
48767 res->valstack_end = NULL;
48768 res->valstack_bottom = NULL;
48769 res->valstack_top = NULL;
48770 res->callstack = NULL;
48771 res->catchstack = NULL;
48772 res->resumer = NULL;
48773 res->compile_ctx = NULL,
48774#if defined(DUK_USE_HEAPPTR16)
48775 res->strs16 = NULL;
48776#else
48777 res->strs = NULL;
48778#endif
48779 {
48780 int i;
48781 for (i = 0; i < DUK_NUM_BUILTINS; i++) {
48782 res->builtins[i] = NULL;
48783 }
48784 }
48785#endif
48786 /* when nothing is running, API calls are in non-strict mode */
48787 DUK_ASSERT(res->strict == 0);
48788
48789 res->heap = heap;
48790 res->valstack_max = DUK_VALSTACK_DEFAULT_MAX;
48791 res->callstack_max = DUK_CALLSTACK_DEFAULT_MAX;
48792 res->catchstack_max = DUK_CATCHSTACK_DEFAULT_MAX;
48793
48794 return res;
48795}
48796
48797#if 0 /* unused now */
48798DUK_INTERNAL duk_hobject *duk_hobject_alloc_checked(duk_hthread *thr, duk_uint_t hobject_flags) {
48799 duk_hobject *res = duk_hobject_alloc(thr->heap, hobject_flags);
48800 if (!res) {
48801 DUK_ERROR_ALLOC_FAILED(thr);
48802 }
48803 return res;
48804}
48805#endif
48806
48807/*
48808 * Allocate a new array.
48809 */
48810
48811DUK_INTERNAL duk_harray *duk_harray_alloc(duk_heap *heap, duk_uint_t hobject_flags) {
48812 duk_harray *res;
48813
48814 res = (duk_harray *) DUK_ALLOC(heap, sizeof(duk_harray));
48815 if (!res) {
48816 return NULL;
48817 }
48818 DUK_MEMZERO(res, sizeof(duk_harray));
48819
48820 duk__init_object_parts(heap, &res->obj, hobject_flags);
48821
48822 DUK_ASSERT(res->length == 0);
48823
48824 return res;
48825}
48826/*
48827 * Object enumeration support.
48828 *
48829 * Creates an internal enumeration state object to be used e.g. with for-in
48830 * enumeration. The state object contains a snapshot of target object keys
48831 * and internal control state for enumeration. Enumerator flags allow caller
48832 * to e.g. request internal/non-enumerable properties, and to enumerate only
48833 * "own" properties.
48834 *
48835 * Also creates the result value for e.g. Object.keys() based on the same
48836 * internal structure.
48837 *
48838 * This snapshot-based enumeration approach is used to simplify enumeration:
48839 * non-snapshot-based approaches are difficult to reconcile with mutating
48840 * the enumeration target, running multiple long-lived enumerators at the
48841 * same time, garbage collection details, etc. The downside is that the
48842 * enumerator object is memory inefficient especially for iterating arrays.
48843 */
48844
48845/* #include duk_internal.h -> already included */
48846
48847/* XXX: identify enumeration target with an object index (not top of stack) */
48848
48849/* First enumerated key index in enumerator object, must match exactly the
48850 * number of control properties inserted to the enumerator.
48851 */
48852#define DUK__ENUM_START_INDEX 2
48853
48854#if 0
48855/* Current implementation suffices for ES2015 for now because there's no symbol
48856 * sorting, so commented out for now.
48857 */
48858
48859/*
48860 * Helper to sort enumeration keys using a callback for pairwise duk_hstring
48861 * comparisons. The keys are in the enumeration object entry part, starting
48862 * from DUK__ENUM_START_INDEX, and the entry part is dense. Entry part values
48863 * are all "true", e.g. "1" -> true, "3" -> true, "foo" -> true "2" -> true,
48864 * so it suffices to just switch keys without switching values.
48865 *
48866 * Insertion sort is used because (1) it's simple and compact, (2) works
48867 * in-place, (3) minimizes operations if data is already nearly sorted,
48868 * (4) doesn't reorder elements considered equal.
48869 * http://en.wikipedia.org/wiki/Insertion_sort
48870 */
48871
48872typedef duk_bool_t (*duk__sort_compare_fn)(duk_hstring *a, duk_hstring *b, duk_uarridx_t val_b);
48873
48874DUK_LOCAL duk_bool_t duk__sort_compare_es6(duk_hstring *a, duk_hstring *b, duk_uarridx_t val_b) {
48875 duk_uarridx_t val_a;
48876
48877 DUK_ASSERT(a != NULL);
48878 DUK_ASSERT(b != NULL);
48879 DUK_UNREF(b); /* Not actually needed now, val_b suffices. */
48880
48881 /* ES2015 [[OwnPropertyKeys]] enumeration order for ordinary objects:
48882 * (1) array indices in ascending order, (2) non-array-index keys in
48883 * insertion order, symbols in insertion order:
48884 * http://www.ecma-international.org/ecma-262/6.0/#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys.
48885 *
48886 * This rule is applied to "own properties" at each inheritance level;
48887 * non-duplicate parent keys always follow child keys. For example,
48888 * an inherited array index will enumerate -after- a symbol in the
48889 * child.
48890 */
48891
48892 val_a = DUK_HSTRING_GET_ARRIDX_FAST(a);
48893
48894 if (val_b < val_a) {
48895 /* Covers:
48896 * - Both keys are array indices and a > b: don't insert here.
48897 * - 'b' is array index, 'a' is not: don't insert here.
48898 */
48899 return 0;
48900 } else {
48901 /* Covers:
48902 * val_a < val_b where:
48903 * - Both keys are array indices and a < b: insert here.
48904 * - 'a' is array index, 'b' is not: insert here.
48905 * val_a == val_b where:
48906 * - Both keys are array indices and a == b: insert here
48907 * (shouldn't actually happen, can't have non-duplicate
48908 * identical array index keys).
48909 * - Neither key is an array index: insert here, keeps key
48910 * order regardless of the keys themselves.
48911 */
48912 return 1;
48913 }
48914}
48915
48916DUK_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) {
48917 duk_hstring **keys;
48918 duk_int_fast32_t idx;
48919
48920 DUK_ASSERT(h_obj != NULL);
48921 DUK_ASSERT(idx_start >= DUK__ENUM_START_INDEX);
48922 DUK_ASSERT(idx_end >= idx_start);
48923 DUK_UNREF(thr);
48924
48925 if (idx_end <= idx_start + 1) {
48926 return; /* Zero or one element(s). */
48927 }
48928
48929 keys = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, h_obj);
48930
48931 for (idx = idx_start + 1; idx < idx_end; idx++) {
48932 duk_hstring *h_curr;
48933 duk_int_fast32_t idx_insert;
48934 duk_uarridx_t val_curr;
48935
48936 h_curr = keys[idx];
48937 DUK_ASSERT(h_curr != NULL);
48938
48939 /* Scan backwards for insertion place. This works very well
48940 * when the elements are nearly in order which is the common
48941 * (and optimized for) case.
48942 */
48943
48944 val_curr = DUK_HSTRING_GET_ARRIDX_FAST(h_curr); /* Remains same during scanning. */
48945 for (idx_insert = idx - 1; idx_insert >= idx_start; idx_insert--) {
48946 duk_hstring *h_insert;
48947 h_insert = keys[idx_insert];
48948 DUK_ASSERT(h_insert != NULL);
48949
48950 /* XXX: fixed callback rather than a callback argument; only
48951 * one argument used and using a callback argument doesn't
48952 * cause e.g. gcc to inline the callback.
48953 */
48954 if (duk__sort_compare_es6(h_insert, h_curr, val_curr)) {
48955 break;
48956 }
48957 }
48958 /* If we're out of indices, idx_insert == idx_start - 1 and idx_insert++
48959 * brings us back to idx_start.
48960 */
48961 idx_insert++;
48962 DUK_ASSERT(idx_insert >= 0 && idx_insert <= idx);
48963
48964 /* .-- p_insert .-- p_curr
48965 * v v
48966 * | ... | insert | ... | curr
48967 */
48968
48969 /* This could also done when the keys are in order, i.e.
48970 * idx_insert == idx. The result would be an unnecessary
48971 * memmove() but we use an explicit check because the keys
48972 * are very often in order already.
48973 */
48974 if (idx != idx_insert) {
48975 DUK_MEMMOVE((void *) (keys + idx_insert + 1),
48976 (const void *) (keys + idx_insert),
48977 (size_t) ((idx - idx_insert) * sizeof(duk_hstring *)));
48978 keys[idx_insert] = h_curr;
48979 }
48980 }
48981}
48982#endif /* disabled */
48983
48984/*
48985 * Helper to sort keys into ES2015 [[OwnPropertyKeys]] enumeration order:
48986 * array keys in ascending order first, followed by keys in insertion
48987 * order, followed by symbols in insertion order (not handled here).
48988 * Insertion sort based.
48989 *
48990 * This algorithm nominally sorts array indices, but because the "no array
48991 * index" marker is higher than any array index, non-array-index keys are
48992 * sorted after array indices. Non-array-index keys are also considered
48993 * equal for sorting which means that their order is kept as is, so the end
48994 * result matches ES2015 [[OwnPropertyKeys]].
48995 *
48996 * Insertion sort is used because (1) it's simple and compact, (2) works
48997 * in-place, (3) minimizes operations if data is already nearly sorted,
48998 * (4) doesn't reorder elements considered equal.
48999 * http://en.wikipedia.org/wiki/Insertion_sort
49000 */
49001
49002DUK_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) {
49003 duk_hstring **keys;
49004 duk_hstring **p_curr, **p_insert, **p_end;
49005 duk_hstring *h_curr;
49006 duk_uarridx_t val_highest, val_curr, val_insert;
49007
49008 DUK_ASSERT(h_obj != NULL);
49009 DUK_ASSERT(idx_start >= DUK__ENUM_START_INDEX);
49010 DUK_ASSERT(idx_end >= idx_start);
49011 DUK_UNREF(thr);
49012
49013 if (idx_end <= idx_start + 1) {
49014 return; /* Zero or one element(s). */
49015 }
49016
49017 keys = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, h_obj);
49018 p_curr = keys + idx_start;
49019 val_highest = DUK_HSTRING_GET_ARRIDX_SLOW(*p_curr);
49020 for (p_curr++, p_end = keys + idx_end; p_curr < p_end; p_curr++) {
49021 DUK_ASSERT(*p_curr != NULL);
49022 val_curr = DUK_HSTRING_GET_ARRIDX_SLOW(*p_curr);
49023
49024 if (val_curr >= val_highest) {
49025 val_highest = val_curr;
49026 continue;
49027 }
49028
49029 /* Needs to be inserted; scan backwards, since we optimize
49030 * for the case where elements are nearly in order.
49031 */
49032
49033 p_insert = p_curr;
49034 for (;;) {
49035 p_insert--; /* Start from p_curr - 1. */
49036 val_insert = DUK_HSTRING_GET_ARRIDX_SLOW(*p_insert);
49037 if (val_insert < val_curr) {
49038 p_insert++;
49039 break;
49040 }
49041 if (p_insert == keys + idx_start) {
49042 break;
49043 }
49044 }
49045
49046 /* .-- p_insert .-- p_curr
49047 * v v
49048 * | ... | insert | ... | curr
49049 */
49050
49051 h_curr = *p_curr;
49052 DUK_MEMMOVE((void *) (p_insert + 1),
49053 (const void *) p_insert,
49054 (size_t) ((p_curr - p_insert) * sizeof(duk_hstring *)));
49055 *p_insert = h_curr;
49056 /* keep val_highest */
49057 }
49058}
49059
49060/*
49061 * Create an internal enumerator object E, which has its keys ordered
49062 * to match desired enumeration ordering. Also initialize internal control
49063 * properties for enumeration.
49064 *
49065 * Note: if an array was used to hold enumeration keys instead, an array
49066 * scan would be needed to eliminate duplicates found in the prototype chain.
49067 */
49068
49069DUK_LOCAL void duk__add_enum_key(duk_context *ctx, duk_hstring *k) {
49070 duk_push_hstring(ctx, k);
49071 duk_push_true(ctx);
49072 duk_put_prop(ctx, -3);
49073}
49074
49075DUK_LOCAL void duk__add_enum_key_stridx(duk_context *ctx, duk_small_uint_t stridx) {
49076 duk__add_enum_key(ctx, DUK_HTHREAD_GET_STRING((duk_hthread *) ctx, stridx));
49077}
49078
49079DUK_INTERNAL void duk_hobject_enumerator_create(duk_context *ctx, duk_small_uint_t enum_flags) {
49080 duk_hthread *thr = (duk_hthread *) ctx;
49081 duk_hobject *enum_target;
49082 duk_hobject *curr;
49083 duk_hobject *res;
49084#if defined(DUK_USE_ES6_PROXY)
49085 duk_hobject *h_proxy_target;
49086 duk_hobject *h_proxy_handler;
49087 duk_hobject *h_trap_result;
49088#endif
49089 duk_uint_fast32_t i, len; /* used for array, stack, and entry indices */
49090 duk_uint_fast32_t sort_start_index;
49091
49092 DUK_ASSERT(ctx != NULL);
49093
49094 enum_target = duk_require_hobject(ctx, -1);
49095 DUK_ASSERT(enum_target != NULL);
49096
49097 duk_push_bare_object(ctx);
49098 res = duk_known_hobject(ctx, -1);
49099
49100 /* [enum_target res] */
49101
49102 /* Target must be stored so that we can recheck whether or not
49103 * keys still exist when we enumerate. This is not done if the
49104 * enumeration result comes from a proxy trap as there is no
49105 * real object to check against.
49106 */
49107 duk_push_hobject(ctx, enum_target);
49108 duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_TARGET);
49109
49110 /* Initialize index so that we skip internal control keys. */
49111 duk_push_int(ctx, DUK__ENUM_START_INDEX);
49112 duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_NEXT);
49113
49114 /*
49115 * Proxy object handling
49116 */
49117
49118#if defined(DUK_USE_ES6_PROXY)
49119 if (DUK_LIKELY((enum_flags & DUK_ENUM_NO_PROXY_BEHAVIOR) != 0)) {
49120 goto skip_proxy;
49121 }
49122 if (DUK_LIKELY(!duk_hobject_proxy_check(thr,
49123 enum_target,
49124 &h_proxy_target,
49125 &h_proxy_handler))) {
49126 goto skip_proxy;
49127 }
49128
49129 /* XXX: share code with Object.keys() Proxy handling */
49130
49131 /* In ES2015 for-in invoked the "enumerate" trap; in ES2016 "enumerate"
49132 * has been obsoleted and "ownKeys" is used instead.
49133 */
49134 DUK_DDD(DUK_DDDPRINT("proxy enumeration"));
49135 duk_push_hobject(ctx, h_proxy_handler);
49136 if (!duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_OWN_KEYS)) {
49137 /* No need to replace the 'enum_target' value in stack, only the
49138 * enum_target reference. This also ensures that the original
49139 * enum target is reachable, which keeps the proxy and the proxy
49140 * target reachable. We do need to replace the internal _Target.
49141 */
49142 DUK_DDD(DUK_DDDPRINT("no ownKeys trap, enumerate proxy target instead"));
49143 DUK_DDD(DUK_DDDPRINT("h_proxy_target=%!O", (duk_heaphdr *) h_proxy_target));
49144 enum_target = h_proxy_target;
49145
49146 duk_push_hobject(ctx, enum_target); /* -> [ ... enum_target res handler undefined target ] */
49147 duk_put_prop_stridx_short(ctx, -4, DUK_STRIDX_INT_TARGET);
49148
49149 duk_pop_2(ctx); /* -> [ ... enum_target res ] */
49150 goto skip_proxy;
49151 }
49152
49153 /* [ ... enum_target res handler trap ] */
49154 duk_insert(ctx, -2);
49155 duk_push_hobject(ctx, h_proxy_target); /* -> [ ... enum_target res trap handler target ] */
49156 duk_call_method(ctx, 1 /*nargs*/); /* -> [ ... enum_target res trap_result ] */
49157 h_trap_result = duk_require_hobject(ctx, -1);
49158 DUK_UNREF(h_trap_result);
49159
49160 duk_proxy_ownkeys_postprocess(ctx, h_proxy_target, enum_flags);
49161 /* -> [ ... enum_target res trap_result keys_array ] */
49162
49163 /* Copy cleaned up trap result keys into the enumerator object. */
49164 /* XXX: result is a dense array; could make use of that. */
49165 DUK_ASSERT(duk_is_array(ctx, -1));
49166 len = (duk_uint_fast32_t) duk_get_length(ctx, -1);
49167 for (i = 0; i < len; i++) {
49168 (void) duk_get_prop_index(ctx, -1, i);
49169 DUK_ASSERT(duk_is_string(ctx, -1)); /* postprocess cleaned up */
49170 /* [ ... enum_target res trap_result keys_array val ] */
49171 duk_push_true(ctx);
49172 /* [ ... enum_target res trap_result keys_array val true ] */
49173 duk_put_prop(ctx, -5);
49174 }
49175 /* [ ... enum_target res trap_result keys_array ] */
49176 duk_pop_2(ctx);
49177 duk_remove_m2(ctx);
49178
49179 /* [ ... res ] */
49180
49181 /* The internal _Target property is kept pointing to the original
49182 * enumeration target (the proxy object), so that the enumerator
49183 * 'next' operation can read property values if so requested. The
49184 * fact that the _Target is a proxy disables key existence check
49185 * during enumeration.
49186 */
49187 DUK_DDD(DUK_DDDPRINT("proxy enumeration, final res: %!O", (duk_heaphdr *) res));
49188 goto compact_and_return;
49189
49190 skip_proxy:
49191#endif /* DUK_USE_ES6_PROXY */
49192
49193 curr = enum_target;
49194 sort_start_index = DUK__ENUM_START_INDEX;
49195 DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(res) == DUK__ENUM_START_INDEX);
49196 while (curr) {
49197 duk_uint_fast32_t sort_end_index;
49198#if !defined(DUK_USE_PREFER_SIZE)
49199 duk_bool_t need_sort = 0;
49200#endif
49201
49202 /* Enumeration proceeds by inheritance level. Virtual
49203 * properties need to be handled specially, followed by
49204 * array part, and finally entry part.
49205 *
49206 * If there are array index keys in the entry part or any
49207 * other risk of the ES2015 [[OwnPropertyKeys]] order being
49208 * violated, need_sort is set and an explicit ES2015 sort is
49209 * done for the inheritance level.
49210 */
49211
49212 /* XXX: inheriting from proxy */
49213
49214 /*
49215 * Virtual properties.
49216 *
49217 * String and buffer indices are virtual and always enumerable,
49218 * 'length' is virtual and non-enumerable. Array and arguments
49219 * object props have special behavior but are concrete.
49220 *
49221 * String and buffer objects don't have an array part so as long
49222 * as virtual array index keys are enumerated first, we don't
49223 * need to set need_sort.
49224 */
49225
49226#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
49227 if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr) || DUK_HOBJECT_IS_BUFOBJ(curr)) {
49228#else
49229 if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr)) {
49230#endif
49231 duk_bool_t have_length = 1;
49232
49233 /* String and buffer enumeration behavior is identical now,
49234 * so use shared handler.
49235 */
49236 if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(curr)) {
49237 duk_hstring *h_val;
49238 h_val = duk_hobject_get_internal_value_string(thr->heap, curr);
49239 DUK_ASSERT(h_val != NULL); /* string objects must not created without internal value */
49240 len = (duk_uint_fast32_t) DUK_HSTRING_GET_CHARLEN(h_val);
49241 }
49242#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
49243 else {
49244 duk_hbufobj *h_bufobj;
49245 DUK_ASSERT(DUK_HOBJECT_IS_BUFOBJ(curr));
49246 h_bufobj = (duk_hbufobj *) curr;
49247
49248 if (h_bufobj == NULL || !h_bufobj->is_typedarray) {
49249 /* Zero length seems like a good behavior for neutered buffers.
49250 * ArrayBuffer (non-view) and DataView don't have index properties
49251 * or .length property.
49252 */
49253 len = 0;
49254 have_length = 0;
49255 } else {
49256 /* There's intentionally no check for
49257 * current underlying buffer length.
49258 */
49259 len = (duk_uint_fast32_t) (h_bufobj->length >> h_bufobj->shift);
49260 }
49261 }
49262#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
49263
49264 for (i = 0; i < len; i++) {
49265 duk_hstring *k;
49266
49267 /* This is a bit fragile: the string is not
49268 * reachable until it is pushed by the helper.
49269 */
49270 k = duk_heap_string_intern_u32_checked(thr, i);
49271 DUK_ASSERT(k);
49272
49273 duk__add_enum_key(ctx, k);
49274
49275 /* [enum_target res] */
49276 }
49277
49278 /* 'length' and other virtual properties are not
49279 * enumerable, but are included if non-enumerable
49280 * properties are requested.
49281 */
49282
49283 if (have_length && (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE)) {
49284 duk__add_enum_key_stridx(ctx, DUK_STRIDX_LENGTH);
49285 }
49286 } else if (DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(curr)) {
49287 if (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE) {
49288 duk__add_enum_key_stridx(ctx, DUK_STRIDX_LENGTH);
49289 }
49290 }
49291
49292 /*
49293 * Array part
49294 */
49295
49296 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ASIZE(curr); i++) {
49297 duk_hstring *k;
49298 duk_tval *tv;
49299
49300 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, curr, i);
49301 if (DUK_TVAL_IS_UNUSED(tv)) {
49302 continue;
49303 }
49304 k = duk_heap_string_intern_u32_checked(thr, i); /* Fragile reachability. */
49305 DUK_ASSERT(k);
49306
49307 duk__add_enum_key(ctx, k);
49308
49309 /* [enum_target res] */
49310 }
49311
49312 if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(curr)) {
49313 /* Array .length comes after numeric indices. */
49314 if (enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE) {
49315 duk__add_enum_key_stridx(ctx, DUK_STRIDX_LENGTH);
49316 }
49317 }
49318
49319 /*
49320 * Entries part
49321 */
49322
49323 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(curr); i++) {
49324 duk_hstring *k;
49325
49326 k = DUK_HOBJECT_E_GET_KEY(thr->heap, curr, i);
49327 if (!k) {
49328 continue;
49329 }
49330 if (!(enum_flags & DUK_ENUM_INCLUDE_NONENUMERABLE) &&
49331 !DUK_HOBJECT_E_SLOT_IS_ENUMERABLE(thr->heap, curr, i)) {
49332 continue;
49333 }
49334 if (DUK_HSTRING_HAS_SYMBOL(k)) {
49335 if (!(enum_flags & DUK_ENUM_INCLUDE_HIDDEN) &&
49336 DUK_HSTRING_HAS_HIDDEN(k)) {
49337 continue;
49338 }
49339 if (!(enum_flags & DUK_ENUM_INCLUDE_SYMBOLS)) {
49340 continue;
49341 }
49342 } else {
49343 DUK_ASSERT(!DUK_HSTRING_HAS_HIDDEN(k)); /* would also have symbol flag */
49344 if (enum_flags & DUK_ENUM_EXCLUDE_STRINGS) {
49345 continue;
49346 }
49347 }
49348 if (DUK_HSTRING_HAS_ARRIDX(k)) {
49349 /* This in currently only possible if the
49350 * object has no array part: the array part
49351 * is exhaustive when it is present.
49352 */
49353#if !defined(DUK_USE_PREFER_SIZE)
49354 need_sort = 1;
49355#endif
49356 } else {
49357 if (enum_flags & DUK_ENUM_ARRAY_INDICES_ONLY) {
49358 continue;
49359 }
49360 }
49361
49362 DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, curr, i) ||
49363 !DUK_TVAL_IS_UNUSED(&DUK_HOBJECT_E_GET_VALUE_PTR(thr->heap, curr, i)->v));
49364
49365 duk__add_enum_key(ctx, k);
49366
49367 /* [enum_target res] */
49368 }
49369
49370 /* Sort enumerated keys according to ES2015 requirements for
49371 * the "inheritance level" just processed. This is far from
49372 * optimal, ES2015 semantics could be achieved more efficiently
49373 * by handling array index string keys (and symbol keys)
49374 * specially above in effect doing the sort inline.
49375 *
49376 * Skip the sort if array index sorting is requested because
49377 * we must consider all keys, also inherited, so an explicit
49378 * sort is done for the whole result after we're done with the
49379 * prototype chain.
49380 *
49381 * Also skip the sort if need_sort == 0, i.e. we know for
49382 * certain that the enumerated order is already correct.
49383 */
49384 sort_end_index = DUK_HOBJECT_GET_ENEXT(res);
49385
49386 if (!(enum_flags & DUK_ENUM_SORT_ARRAY_INDICES)) {
49387#if defined(DUK_USE_PREFER_SIZE)
49388 duk__sort_enum_keys_es6(thr, res, sort_start_index, sort_end_index);
49389#else
49390 if (need_sort) {
49391 DUK_DDD(DUK_DDDPRINT("need to sort"));
49392 duk__sort_enum_keys_es6(thr, res, sort_start_index, sort_end_index);
49393 } else {
49394 DUK_DDD(DUK_DDDPRINT("no need to sort"));
49395 }
49396#endif
49397 }
49398
49399 sort_start_index = sort_end_index;
49400
49401 if (enum_flags & DUK_ENUM_OWN_PROPERTIES_ONLY) {
49402 break;
49403 }
49404
49405 curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
49406 }
49407
49408 /* [enum_target res] */
49409
49410 duk_remove_m2(ctx);
49411
49412 /* [res] */
49413
49414 if (enum_flags & DUK_ENUM_SORT_ARRAY_INDICES) {
49415 /* Some E5/E5.1 algorithms require that array indices are iterated
49416 * in a strictly ascending order. This is the case for e.g.
49417 * Array.prototype.forEach() and JSON.stringify() PropertyList
49418 * handling. The caller can request an explicit sort in these
49419 * cases.
49420 */
49421
49422 /* Sort to ES2015 order which works for pure array incides but
49423 * also for mixed keys.
49424 */
49425 duk__sort_enum_keys_es6(thr, res, DUK__ENUM_START_INDEX, DUK_HOBJECT_GET_ENEXT(res));
49426 }
49427
49428#if defined(DUK_USE_ES6_PROXY)
49429 compact_and_return:
49430#endif
49431 /* compact; no need to seal because object is internal */
49432 duk_hobject_compact_props(thr, res);
49433
49434 DUK_DDD(DUK_DDDPRINT("created enumerator object: %!iT", (duk_tval *) duk_get_tval(ctx, -1)));
49435}
49436
49437/*
49438 * Returns non-zero if a key and/or value was enumerated, and:
49439 *
49440 * [enum] -> [key] (get_value == 0)
49441 * [enum] -> [key value] (get_value == 1)
49442 *
49443 * Returns zero without pushing anything on the stack otherwise.
49444 */
49445DUK_INTERNAL duk_bool_t duk_hobject_enumerator_next(duk_context *ctx, duk_bool_t get_value) {
49446 duk_hthread *thr = (duk_hthread *) ctx;
49447 duk_hobject *e;
49448 duk_hobject *enum_target;
49449 duk_hstring *res = NULL;
49450 duk_uint_fast32_t idx;
49451 duk_bool_t check_existence;
49452
49453 DUK_ASSERT(ctx != NULL);
49454
49455 /* [... enum] */
49456
49457 e = duk_require_hobject(ctx, -1);
49458
49459 /* XXX use get tval ptr, more efficient */
49460 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_NEXT);
49461 idx = (duk_uint_fast32_t) duk_require_uint(ctx, -1);
49462 duk_pop(ctx);
49463 DUK_DDD(DUK_DDDPRINT("enumeration: index is: %ld", (long) idx));
49464
49465 /* Enumeration keys are checked against the enumeration target (to see
49466 * that they still exist). In the proxy enumeration case _Target will
49467 * be the proxy, and checking key existence against the proxy is not
49468 * required (or sensible, as the keys may be fully virtual).
49469 */
49470 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_TARGET);
49471 enum_target = duk_require_hobject(ctx, -1);
49472 DUK_ASSERT(enum_target != NULL);
49473#if defined(DUK_USE_ES6_PROXY)
49474 check_existence = (!DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(enum_target));
49475#else
49476 check_existence = 1;
49477#endif
49478 duk_pop(ctx); /* still reachable */
49479
49480 DUK_DDD(DUK_DDDPRINT("getting next enum value, enum_target=%!iO, enumerator=%!iT",
49481 (duk_heaphdr *) enum_target, (duk_tval *) duk_get_tval(ctx, -1)));
49482
49483 /* no array part */
49484 for (;;) {
49485 duk_hstring *k;
49486
49487 if (idx >= DUK_HOBJECT_GET_ENEXT(e)) {
49488 DUK_DDD(DUK_DDDPRINT("enumeration: ran out of elements"));
49489 break;
49490 }
49491
49492 /* we know these because enum objects are internally created */
49493 k = DUK_HOBJECT_E_GET_KEY(thr->heap, e, idx);
49494 DUK_ASSERT(k != NULL);
49495 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, e, idx));
49496 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(&DUK_HOBJECT_E_GET_VALUE(thr->heap, e, idx).v));
49497
49498 idx++;
49499
49500 /* recheck that the property still exists */
49501 if (check_existence && !duk_hobject_hasprop_raw(thr, enum_target, k)) {
49502 DUK_DDD(DUK_DDDPRINT("property deleted during enumeration, skip"));
49503 continue;
49504 }
49505
49506 DUK_DDD(DUK_DDDPRINT("enumeration: found element, key: %!O", (duk_heaphdr *) k));
49507 res = k;
49508 break;
49509 }
49510
49511 DUK_DDD(DUK_DDDPRINT("enumeration: updating next index to %ld", (long) idx));
49512
49513 duk_push_u32(ctx, (duk_uint32_t) idx);
49514 duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_NEXT);
49515
49516 /* [... enum] */
49517
49518 if (res) {
49519 duk_push_hstring(ctx, res);
49520 if (get_value) {
49521 duk_push_hobject(ctx, enum_target);
49522 duk_dup_m2(ctx); /* -> [... enum key enum_target key] */
49523 duk_get_prop(ctx, -2); /* -> [... enum key enum_target val] */
49524 duk_remove_m2(ctx); /* -> [... enum key val] */
49525 duk_remove(ctx, -3); /* -> [... key val] */
49526 } else {
49527 duk_remove_m2(ctx); /* -> [... key] */
49528 }
49529 return 1;
49530 } else {
49531 duk_pop(ctx); /* -> [...] */
49532 return 0;
49533 }
49534}
49535
49536/*
49537 * Get enumerated keys in an Ecmascript array. Matches Object.keys() behavior
49538 * described in E5 Section 15.2.3.14.
49539 */
49540
49541DUK_INTERNAL duk_ret_t duk_hobject_get_enumerated_keys(duk_context *ctx, duk_small_uint_t enum_flags) {
49542 duk_hthread *thr = (duk_hthread *) ctx;
49543 duk_hobject *e;
49544 duk_harray *a;
49545 duk_hstring **keys;
49546 duk_tval *tv;
49547 duk_uint_fast32_t count;
49548
49549 DUK_ASSERT(ctx != NULL);
49550 DUK_ASSERT(duk_get_hobject(ctx, -1) != NULL);
49551 DUK_UNREF(thr);
49552
49553 /* Create a temporary enumerator to get the (non-duplicated) key list;
49554 * the enumerator state is initialized without being needed, but that
49555 * has little impact.
49556 */
49557
49558 duk_hobject_enumerator_create(ctx, enum_flags);
49559 e = duk_known_hobject(ctx, -1);
49560
49561 /* [enum_target enum res] */
49562
49563 /* Create dense result array to exact size. */
49564 DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(e) >= DUK__ENUM_START_INDEX);
49565 count = (duk_uint32_t) (DUK_HOBJECT_GET_ENEXT(e) - DUK__ENUM_START_INDEX);
49566
49567 a = duk_push_harray_with_size(ctx, count);
49568 DUK_ASSERT(a != NULL);
49569 DUK_ASSERT(DUK_HOBJECT_GET_ASIZE((duk_hobject *) a) == count);
49570 DUK_ASSERT(a->length == count);
49571 tv = DUK_HOBJECT_A_GET_BASE(thr->heap, (duk_hobject *) a);
49572
49573 /* Fill result array, no side effects. */
49574
49575 keys = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, e);
49576 keys += DUK__ENUM_START_INDEX;
49577
49578 while (count-- > 0) {
49579 duk_hstring *k;
49580
49581 k = *keys++;
49582 DUK_ASSERT(k != NULL); /* enumerator must have no keys deleted */
49583
49584 DUK_TVAL_SET_STRING(tv, k);
49585 tv++;
49586 DUK_HSTRING_INCREF(thr, k);
49587 }
49588
49589 /* [enum_target enum res] */
49590 duk_remove_m2(ctx);
49591
49592 /* [enum_target res] */
49593
49594 return 1; /* return 1 to allow callers to tail call */
49595}
49596
49597/* automatic undefs */
49598#undef DUK__ENUM_START_INDEX
49599/*
49600 * Run an duk_hobject finalizer. Used for both reference counting
49601 * and mark-and-sweep algorithms. Must never throw an error.
49602 *
49603 * There is no return value. Any return value or error thrown by
49604 * the finalizer is ignored (although errors are debug logged).
49605 *
49606 * Notes:
49607 *
49608 * - The thread used for calling the finalizer is the same as the
49609 * 'thr' argument. This may need to change later.
49610 *
49611 * - The finalizer thread 'top' assertions are there because it is
49612 * critical that strict stack policy is observed (i.e. no cruft
49613 * left on the finalizer stack).
49614 */
49615
49616/* #include duk_internal.h -> already included */
49617
49618#if defined(DUK_USE_FINALIZER_SUPPORT)
49619DUK_LOCAL duk_ret_t duk__finalize_helper(duk_context *ctx, void *udata) {
49620 duk_hthread *thr;
49621
49622 DUK_ASSERT(ctx != NULL);
49623 thr = (duk_hthread *) ctx;
49624 DUK_UNREF(udata);
49625
49626 DUK_DDD(DUK_DDDPRINT("protected finalization helper running"));
49627
49628 /* [... obj] */
49629
49630 /* XXX: Finalizer lookup should traverse the prototype chain (to allow
49631 * inherited finalizers) but should not invoke accessors or proxy object
49632 * behavior. At the moment this lookup will invoke proxy behavior, so
49633 * caller must ensure that this function is not called if the target is
49634 * a Proxy.
49635 */
49636
49637 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_FINALIZER); /* -> [... obj finalizer] */
49638 if (!duk_is_callable(ctx, -1)) {
49639 DUK_DDD(DUK_DDDPRINT("-> no finalizer or finalizer not callable"));
49640 return 0;
49641 }
49642 duk_dup_m2(ctx);
49643 duk_push_boolean(ctx, DUK_HEAP_HAS_FINALIZER_NORESCUE(thr->heap));
49644 DUK_DDD(DUK_DDDPRINT("-> finalizer found, calling finalizer"));
49645 duk_call(ctx, 2); /* [ ... obj finalizer obj heapDestruct ] -> [ ... obj retval ] */
49646 DUK_DDD(DUK_DDDPRINT("finalizer finished successfully"));
49647 return 0;
49648
49649 /* Note: we rely on duk_safe_call() to fix up the stack for the caller,
49650 * so we don't need to pop stuff here. There is no return value;
49651 * caller determines rescued status based on object refcount.
49652 */
49653}
49654
49655DUK_INTERNAL void duk_hobject_run_finalizer(duk_hthread *thr, duk_hobject *obj) {
49656 duk_context *ctx = (duk_context *) thr;
49657 duk_ret_t rc;
49658#if defined(DUK_USE_ASSERTIONS)
49659 duk_idx_t entry_top;
49660#endif
49661
49662 DUK_DDD(DUK_DDDPRINT("running object finalizer for object: %p", (void *) obj));
49663
49664 DUK_ASSERT(thr != NULL);
49665 DUK_ASSERT(ctx != NULL);
49666 DUK_ASSERT(obj != NULL);
49667 DUK_ASSERT_VALSTACK_SPACE(thr, 1);
49668
49669#if defined(DUK_USE_ASSERTIONS)
49670 entry_top = duk_get_top(ctx);
49671#endif
49672 /*
49673 * Get and call the finalizer. All of this must be wrapped
49674 * in a protected call, because even getting the finalizer
49675 * may trigger an error (getter may throw one, for instance).
49676 */
49677
49678 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
49679 if (DUK_HEAPHDR_HAS_FINALIZED((duk_heaphdr *) obj)) {
49680 DUK_D(DUK_DPRINT("object already finalized, avoid running finalizer twice: %!O", obj));
49681 return;
49682 }
49683 DUK_HEAPHDR_SET_FINALIZED((duk_heaphdr *) obj); /* ensure never re-entered until rescue cycle complete */
49684 if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj)) {
49685 /* This shouldn't happen; call sites should avoid looking up
49686 * _Finalizer "through" a Proxy, but ignore if we come here
49687 * with a Proxy to avoid finalizer re-entry.
49688 */
49689 DUK_D(DUK_DPRINT("object is a proxy, skip finalizer call"));
49690 return;
49691 }
49692
49693 /* XXX: use a NULL error handler for the finalizer call? */
49694
49695 DUK_DDD(DUK_DDDPRINT("-> finalizer found, calling wrapped finalize helper"));
49696 duk_push_hobject(ctx, obj); /* this also increases refcount by one */
49697 rc = duk_safe_call(ctx, duk__finalize_helper, NULL /*udata*/, 0 /*nargs*/, 1 /*nrets*/); /* -> [... obj retval/error] */
49698 DUK_ASSERT_TOP(ctx, entry_top + 2); /* duk_safe_call discipline */
49699
49700 if (rc != DUK_EXEC_SUCCESS) {
49701 /* Note: we ask for one return value from duk_safe_call to get this
49702 * error debugging here.
49703 */
49704 DUK_D(DUK_DPRINT("wrapped finalizer call failed for object %p (ignored); error: %!T",
49705 (void *) obj, (duk_tval *) duk_get_tval(ctx, -1)));
49706 }
49707 duk_pop_2(ctx); /* -> [...] */
49708
49709 DUK_ASSERT_TOP(ctx, entry_top);
49710}
49711#endif /* DUK_USE_FINALIZER_SUPPORT */
49712/*
49713 * Misc support functions
49714 */
49715
49716/* #include duk_internal.h -> already included */
49717
49718DUK_INTERNAL duk_bool_t duk_hobject_prototype_chain_contains(duk_hthread *thr, duk_hobject *h, duk_hobject *p, duk_bool_t ignore_loop) {
49719 duk_uint_t sanity;
49720
49721 DUK_ASSERT(thr != NULL);
49722
49723 /* False if the object is NULL or the prototype 'p' is NULL.
49724 * In particular, false if both are NULL (don't compare equal).
49725 */
49726 if (h == NULL || p == NULL) {
49727 return 0;
49728 }
49729
49730 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
49731 do {
49732 if (h == p) {
49733 return 1;
49734 }
49735
49736 if (sanity-- == 0) {
49737 if (ignore_loop) {
49738 break;
49739 } else {
49740 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
49741 }
49742 }
49743 h = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
49744 } while (h);
49745
49746 return 0;
49747}
49748
49749DUK_INTERNAL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p) {
49750#if defined(DUK_USE_REFERENCE_COUNTING)
49751 duk_hobject *tmp;
49752
49753 DUK_ASSERT(h);
49754 tmp = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h);
49755 DUK_HOBJECT_SET_PROTOTYPE(thr->heap, h, p);
49756 DUK_HOBJECT_INCREF_ALLOWNULL(thr, p); /* avoid problems if p == h->prototype */
49757 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
49758#else
49759 DUK_ASSERT(h);
49760 DUK_UNREF(thr);
49761 DUK_HOBJECT_SET_PROTOTYPE(thr->heap, h, p);
49762#endif
49763}
49764/*
49765 * Helpers for creating and querying pc2line debug data, which
49766 * converts a bytecode program counter to a source line number.
49767 *
49768 * The run-time pc2line data is bit-packed, and documented in:
49769 *
49770 * doc/function-objects.rst
49771 */
49772
49773/* #include duk_internal.h -> already included */
49774
49775#if defined(DUK_USE_PC2LINE)
49776
49777/* Generate pc2line data for an instruction sequence, leaving a buffer on stack top. */
49778DUK_INTERNAL void duk_hobject_pc2line_pack(duk_hthread *thr, duk_compiler_instr *instrs, duk_uint_fast32_t length) {
49779 duk_context *ctx = (duk_context *) thr;
49780 duk_hbuffer_dynamic *h_buf;
49781 duk_bitencoder_ctx be_ctx_alloc;
49782 duk_bitencoder_ctx *be_ctx = &be_ctx_alloc;
49783 duk_uint32_t *hdr;
49784 duk_size_t new_size;
49785 duk_uint_fast32_t num_header_entries;
49786 duk_uint_fast32_t curr_offset;
49787 duk_int_fast32_t curr_line, next_line, diff_line;
49788 duk_uint_fast32_t curr_pc;
49789 duk_uint_fast32_t hdr_index;
49790
49791 DUK_ASSERT(length <= DUK_COMPILER_MAX_BYTECODE_LENGTH);
49792
49793 /* XXX: add proper spare handling to dynamic buffer, to minimize
49794 * reallocs; currently there is no spare at all.
49795 */
49796
49797 num_header_entries = (length + DUK_PC2LINE_SKIP - 1) / DUK_PC2LINE_SKIP;
49798 curr_offset = (duk_uint_fast32_t) (sizeof(duk_uint32_t) + num_header_entries * sizeof(duk_uint32_t) * 2);
49799
49800 duk_push_dynamic_buffer(ctx, (duk_size_t) curr_offset);
49801 h_buf = (duk_hbuffer_dynamic *) duk_known_hbuffer(ctx, -1);
49802 DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(h_buf) && !DUK_HBUFFER_HAS_EXTERNAL(h_buf));
49803
49804 hdr = (duk_uint32_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h_buf);
49805 DUK_ASSERT(hdr != NULL);
49806 hdr[0] = (duk_uint32_t) length; /* valid pc range is [0, length[ */
49807
49808 curr_pc = 0U;
49809 while (curr_pc < length) {
49810 new_size = (duk_size_t) (curr_offset + DUK_PC2LINE_MAX_DIFF_LENGTH);
49811 duk_hbuffer_resize(thr, h_buf, new_size);
49812
49813 hdr = (duk_uint32_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, h_buf);
49814 DUK_ASSERT(hdr != NULL);
49815 DUK_ASSERT(curr_pc < length);
49816 hdr_index = 1 + (curr_pc / DUK_PC2LINE_SKIP) * 2;
49817 curr_line = (duk_int_fast32_t) instrs[curr_pc].line;
49818 hdr[hdr_index + 0] = (duk_uint32_t) curr_line;
49819 hdr[hdr_index + 1] = (duk_uint32_t) curr_offset;
49820
49821#if 0
49822 DUK_DDD(DUK_DDDPRINT("hdr[%ld]: pc=%ld line=%ld offset=%ld",
49823 (long) (curr_pc / DUK_PC2LINE_SKIP),
49824 (long) curr_pc,
49825 (long) hdr[hdr_index + 0],
49826 (long) hdr[hdr_index + 1]));
49827#endif
49828
49829 DUK_MEMZERO(be_ctx, sizeof(*be_ctx));
49830 be_ctx->data = ((duk_uint8_t *) hdr) + curr_offset;
49831 be_ctx->length = (duk_size_t) DUK_PC2LINE_MAX_DIFF_LENGTH;
49832
49833 for (;;) {
49834 curr_pc++;
49835 if ( ((curr_pc % DUK_PC2LINE_SKIP) == 0) || /* end of diff run */
49836 (curr_pc >= length) ) { /* end of bytecode */
49837 break;
49838 }
49839 DUK_ASSERT(curr_pc < length);
49840 next_line = (duk_int32_t) instrs[curr_pc].line;
49841 diff_line = next_line - curr_line;
49842
49843#if 0
49844 DUK_DDD(DUK_DDDPRINT("curr_line=%ld, next_line=%ld -> diff_line=%ld",
49845 (long) curr_line, (long) next_line, (long) diff_line));
49846#endif
49847
49848 if (diff_line == 0) {
49849 /* 0 */
49850 duk_be_encode(be_ctx, 0, 1);
49851 } else if (diff_line >= 1 && diff_line <= 4) {
49852 /* 1 0 <2 bits> */
49853 duk_be_encode(be_ctx, (0x02 << 2) + (diff_line - 1), 4);
49854 } else if (diff_line >= -0x80 && diff_line <= 0x7f) {
49855 /* 1 1 0 <8 bits> */
49856 DUK_ASSERT(diff_line + 0x80 >= 0 && diff_line + 0x80 <= 0xff);
49857 duk_be_encode(be_ctx, (0x06 << 8) + (diff_line + 0x80), 11);
49858 } else {
49859 /* 1 1 1 <32 bits>
49860 * Encode in two parts to avoid bitencode 24-bit limitation
49861 */
49862 duk_be_encode(be_ctx, (0x07 << 16) + ((next_line >> 16) & 0xffffU), 19);
49863 duk_be_encode(be_ctx, next_line & 0xffffU, 16);
49864 }
49865
49866 curr_line = next_line;
49867 }
49868
49869 duk_be_finish(be_ctx);
49870 DUK_ASSERT(!be_ctx->truncated);
49871
49872 /* be_ctx->offset == length of encoded bitstream */
49873 curr_offset += (duk_uint_fast32_t) be_ctx->offset;
49874 }
49875
49876 /* compact */
49877 new_size = (duk_size_t) curr_offset;
49878 duk_hbuffer_resize(thr, h_buf, new_size);
49879
49880 (void) duk_to_fixed_buffer(ctx, -1, NULL);
49881
49882 DUK_DDD(DUK_DDDPRINT("final pc2line data: pc_limit=%ld, length=%ld, %lf bits/opcode --> %!ixT",
49883 (long) length, (long) new_size, (double) new_size * 8.0 / (double) length,
49884 (duk_tval *) duk_get_tval(ctx, -1)));
49885}
49886
49887/* PC is unsigned. If caller does PC arithmetic and gets a negative result,
49888 * it will map to a large PC which is out of bounds and causes a zero to be
49889 * returned.
49890 */
49891DUK_LOCAL duk_uint_fast32_t duk__hobject_pc2line_query_raw(duk_hthread *thr, duk_hbuffer_fixed *buf, duk_uint_fast32_t pc) {
49892 duk_bitdecoder_ctx bd_ctx_alloc;
49893 duk_bitdecoder_ctx *bd_ctx = &bd_ctx_alloc;
49894 duk_uint32_t *hdr;
49895 duk_uint_fast32_t start_offset;
49896 duk_uint_fast32_t pc_limit;
49897 duk_uint_fast32_t hdr_index;
49898 duk_uint_fast32_t pc_base;
49899 duk_uint_fast32_t n;
49900 duk_uint_fast32_t curr_line;
49901
49902 DUK_ASSERT(buf != NULL);
49903 DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) buf) && !DUK_HBUFFER_HAS_EXTERNAL((duk_hbuffer *) buf));
49904 DUK_UNREF(thr);
49905
49906 /*
49907 * Use the index in the header to find the right starting point
49908 */
49909
49910 hdr_index = pc / DUK_PC2LINE_SKIP;
49911 pc_base = hdr_index * DUK_PC2LINE_SKIP;
49912 n = pc - pc_base;
49913
49914 if (DUK_HBUFFER_FIXED_GET_SIZE(buf) <= sizeof(duk_uint32_t)) {
49915 DUK_DD(DUK_DDPRINT("pc2line lookup failed: buffer is smaller than minimal header"));
49916 goto error;
49917 }
49918
49919 hdr = (duk_uint32_t *) (void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, buf);
49920 pc_limit = hdr[0];
49921 if (pc >= pc_limit) {
49922 /* Note: pc is unsigned and cannot be negative */
49923 DUK_DD(DUK_DDPRINT("pc2line lookup failed: pc out of bounds (pc=%ld, limit=%ld)",
49924 (long) pc, (long) pc_limit));
49925 goto error;
49926 }
49927
49928 curr_line = hdr[1 + hdr_index * 2];
49929 start_offset = hdr[1 + hdr_index * 2 + 1];
49930 if ((duk_size_t) start_offset > DUK_HBUFFER_FIXED_GET_SIZE(buf)) {
49931 DUK_DD(DUK_DDPRINT("pc2line lookup failed: start_offset out of bounds (start_offset=%ld, buffer_size=%ld)",
49932 (long) start_offset, (long) DUK_HBUFFER_GET_SIZE((duk_hbuffer *) buf)));
49933 goto error;
49934 }
49935
49936 /*
49937 * Iterate the bitstream (line diffs) until PC is reached
49938 */
49939
49940 DUK_MEMZERO(bd_ctx, sizeof(*bd_ctx));
49941 bd_ctx->data = ((duk_uint8_t *) hdr) + start_offset;
49942 bd_ctx->length = (duk_size_t) (DUK_HBUFFER_FIXED_GET_SIZE(buf) - start_offset);
49943
49944#if 0
49945 DUK_DDD(DUK_DDDPRINT("pc2line lookup: pc=%ld -> hdr_index=%ld, pc_base=%ld, n=%ld, start_offset=%ld",
49946 (long) pc, (long) hdr_index, (long) pc_base, (long) n, (long) start_offset));
49947#endif
49948
49949 while (n > 0) {
49950#if 0
49951 DUK_DDD(DUK_DDDPRINT("lookup: n=%ld, curr_line=%ld", (long) n, (long) curr_line));
49952#endif
49953
49954 if (duk_bd_decode_flag(bd_ctx)) {
49955 if (duk_bd_decode_flag(bd_ctx)) {
49956 if (duk_bd_decode_flag(bd_ctx)) {
49957 /* 1 1 1 <32 bits> */
49958 duk_uint_fast32_t t;
49959 t = duk_bd_decode(bd_ctx, 16); /* workaround: max nbits = 24 now */
49960 t = (t << 16) + duk_bd_decode(bd_ctx, 16);
49961 curr_line = t;
49962 } else {
49963 /* 1 1 0 <8 bits> */
49964 duk_uint_fast32_t t;
49965 t = duk_bd_decode(bd_ctx, 8);
49966 curr_line = curr_line + t - 0x80;
49967 }
49968 } else {
49969 /* 1 0 <2 bits> */
49970 duk_uint_fast32_t t;
49971 t = duk_bd_decode(bd_ctx, 2);
49972 curr_line = curr_line + t + 1;
49973 }
49974 } else {
49975 /* 0: no change */
49976 }
49977
49978 n--;
49979 }
49980
49981 DUK_DDD(DUK_DDDPRINT("pc2line lookup result: pc %ld -> line %ld", (long) pc, (long) curr_line));
49982 return curr_line;
49983
49984 error:
49985 DUK_D(DUK_DPRINT("pc2line conversion failed for pc=%ld", (long) pc));
49986 return 0;
49987}
49988
49989DUK_INTERNAL duk_uint_fast32_t duk_hobject_pc2line_query(duk_context *ctx, duk_idx_t idx_func, duk_uint_fast32_t pc) {
49990 duk_hbuffer_fixed *pc2line;
49991 duk_uint_fast32_t line;
49992
49993 /* XXX: now that pc2line is used by the debugger quite heavily in
49994 * checked execution, this should be optimized to avoid value stack
49995 * and perhaps also implement some form of pc2line caching (see
49996 * future work in debugger.rst).
49997 */
49998
49999 duk_get_prop_stridx(ctx, idx_func, DUK_STRIDX_INT_PC2LINE);
50000 pc2line = (duk_hbuffer_fixed *) duk_get_hbuffer(ctx, -1);
50001 if (pc2line != NULL) {
50002 DUK_ASSERT(!DUK_HBUFFER_HAS_DYNAMIC((duk_hbuffer *) pc2line) && !DUK_HBUFFER_HAS_EXTERNAL((duk_hbuffer *) pc2line));
50003 line = duk__hobject_pc2line_query_raw((duk_hthread *) ctx, pc2line, (duk_uint_fast32_t) pc);
50004 } else {
50005 line = 0;
50006 }
50007 duk_pop(ctx);
50008
50009 return line;
50010}
50011
50012#endif /* DUK_USE_PC2LINE */
50013/*
50014 * Hobject property set/get functionality.
50015 *
50016 * This is very central functionality for size, performance, and compliance.
50017 * It is also rather intricate; see hobject-algorithms.rst for discussion on
50018 * the algorithms and memory-management.rst for discussion on refcounts and
50019 * side effect issues.
50020 *
50021 * Notes:
50022 *
50023 * - It might be tempting to assert "refcount nonzero" for objects
50024 * being operated on, but that's not always correct: objects with
50025 * a zero refcount may be operated on by the refcount implementation
50026 * (finalization) for instance. Hence, no refcount assertions are made.
50027 *
50028 * - Many operations (memory allocation, identifier operations, etc)
50029 * may cause arbitrary side effects (e.g. through GC and finalization).
50030 * These side effects may invalidate duk_tval pointers which point to
50031 * areas subject to reallocation (like value stack). Heap objects
50032 * themselves have stable pointers. Holding heap object pointers or
50033 * duk_tval copies is not problematic with respect to side effects;
50034 * care must be taken when holding and using argument duk_tval pointers.
50035 *
50036 * - If a finalizer is executed, it may operate on the the same object
50037 * we're currently dealing with. For instance, the finalizer might
50038 * delete a certain property which has already been looked up and
50039 * confirmed to exist. Ideally finalizers would be disabled if GC
50040 * happens during property access. At the moment property table realloc
50041 * disables finalizers, and all DECREFs may cause arbitrary changes so
50042 * handle DECREF carefully.
50043 *
50044 * - The order of operations for a DECREF matters. When DECREF is executed,
50045 * the entire object graph must be consistent; note that a refzero may
50046 * lead to a mark-and-sweep through a refcount finalizer. Use NORZ macros
50047 * and an explicit DUK_REFZERO_CHECK_xxx() if achieving correct order is hard.
50048 */
50049
50050/*
50051 * XXX: array indices are mostly typed as duk_uint32_t here; duk_uarridx_t
50052 * might be more appropriate.
50053 */
50054
50055/*
50056 * XXX: duk_uint_fast32_t should probably be used in many places here.
50057 */
50058
50059/* #include duk_internal.h -> already included */
50060
50061/*
50062 * Local defines
50063 */
50064
50065#define DUK__NO_ARRAY_INDEX DUK_HSTRING_NO_ARRAY_INDEX
50066
50067/* hash probe sequence */
50068#define DUK__HASH_INITIAL(hash,h_size) DUK_HOBJECT_HASH_INITIAL((hash),(h_size))
50069#define DUK__HASH_PROBE_STEP(hash) DUK_HOBJECT_HASH_PROBE_STEP((hash))
50070
50071/* marker values for hash part */
50072#define DUK__HASH_UNUSED DUK_HOBJECT_HASHIDX_UNUSED
50073#define DUK__HASH_DELETED DUK_HOBJECT_HASHIDX_DELETED
50074
50075/* valstack space that suffices for all local calls, including recursion
50076 * of other than Duktape calls (getters etc)
50077 */
50078#define DUK__VALSTACK_SPACE 10
50079
50080/* valstack space allocated especially for proxy lookup which does a
50081 * recursive property lookup
50082 */
50083#define DUK__VALSTACK_PROXY_LOOKUP 20
50084
50085/*
50086 * Local prototypes
50087 */
50088
50089DUK_LOCAL_DECL duk_bool_t duk__check_arguments_map_for_get(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc);
50090DUK_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);
50091DUK_LOCAL_DECL void duk__check_arguments_map_for_delete(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc);
50092
50093DUK_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);
50094DUK_LOCAL_DECL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject *obj);
50095
50096DUK_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);
50097DUK_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);
50098
50099/*
50100 * Misc helpers
50101 */
50102
50103/* Convert a duk_tval number (caller checks) to a 32-bit index. Returns
50104 * DUK__NO_ARRAY_INDEX if the number is not whole or not a valid array
50105 * index.
50106 */
50107/* XXX: for fastints, could use a variant which assumes a double duk_tval
50108 * (and doesn't need to check for fastint again).
50109 */
50110DUK_LOCAL duk_uint32_t duk__tval_number_to_arr_idx(duk_tval *tv) {
50111 duk_double_t dbl;
50112 duk_uint32_t idx;
50113
50114 DUK_ASSERT(tv != NULL);
50115 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
50116
50117 /* -0 is accepted here as index 0 because ToString(-0) == "0" which is
50118 * in canonical form and thus an array index.
50119 */
50120 dbl = DUK_TVAL_GET_NUMBER(tv);
50121 idx = (duk_uint32_t) dbl;
50122 if ((duk_double_t) idx == dbl) {
50123 /* Is whole and within 32 bit range. If the value happens to be 0xFFFFFFFF,
50124 * it's not a valid array index but will then match DUK__NO_ARRAY_INDEX.
50125 */
50126 return idx;
50127 }
50128 return DUK__NO_ARRAY_INDEX;
50129}
50130
50131#if defined(DUK_USE_FASTINT)
50132/* Convert a duk_tval fastint (caller checks) to a 32-bit index. */
50133DUK_LOCAL duk_uint32_t duk__tval_fastint_to_arr_idx(duk_tval *tv) {
50134 duk_int64_t t;
50135
50136 DUK_ASSERT(tv != NULL);
50137 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv));
50138
50139 t = DUK_TVAL_GET_FASTINT(tv);
50140 if ((t & ~0xffffffffULL) != 0) {
50141 /* Catches >0x100000000 and negative values. */
50142 return DUK__NO_ARRAY_INDEX;
50143 }
50144
50145 /* If the value happens to be 0xFFFFFFFF, it's not a valid array index
50146 * but will then match DUK__NO_ARRAY_INDEX.
50147 */
50148 return (duk_uint32_t) t;
50149}
50150#endif /* DUK_USE_FASTINT */
50151
50152/* Convert a duk_tval on the value stack (in a trusted index we don't validate)
50153 * to a string or symbol using ES2015 ToPropertyKey():
50154 * http://www.ecma-international.org/ecma-262/6.0/#sec-topropertykey.
50155 *
50156 * Also check if it's a valid array index and return that (or DUK__NO_ARRAY_INDEX
50157 * if not).
50158 */
50159DUK_LOCAL duk_uint32_t duk__to_property_key(duk_context *ctx, duk_idx_t idx, duk_hstring **out_h) {
50160 duk_uint32_t arr_idx;
50161 duk_hstring *h;
50162 duk_tval *tv_dst;
50163
50164 DUK_ASSERT(ctx != NULL);
50165 DUK_ASSERT(out_h != NULL);
50166 DUK_ASSERT(duk_is_valid_index(ctx, idx));
50167 DUK_ASSERT(idx < 0);
50168
50169 /* XXX: The revised ES2015 ToPropertyKey() handling (ES5.1 was just
50170 * ToString()) involves a ToPrimitive(), a symbol check, and finally
50171 * a ToString(). Figure out the best way to have a good fast path
50172 * but still be compliant and share code.
50173 */
50174
50175 tv_dst = DUK_GET_TVAL_NEGIDX((duk_hthread *) ctx, idx); /* intentionally unvalidated */
50176 if (DUK_TVAL_IS_STRING(tv_dst)) {
50177 /* Most important path: strings and plain symbols are used as
50178 * is. For symbols the array index check below is unnecessary
50179 * (they're never valid array indices) but checking that the
50180 * string is a symbol would make the plain string path slower
50181 * unnecessarily.
50182 */
50183 h = DUK_TVAL_GET_STRING(tv_dst);
50184 } else {
50185 h = duk_to_property_key_hstring(ctx, idx);
50186 }
50187 DUK_ASSERT(h != NULL);
50188 *out_h = h;
50189
50190 arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(h);
50191 return arr_idx;
50192}
50193
50194DUK_LOCAL duk_uint32_t duk__push_tval_to_property_key(duk_context *ctx, duk_tval *tv_key, duk_hstring **out_h) {
50195 duk_push_tval(ctx, tv_key); /* XXX: could use an unsafe push here */
50196 return duk__to_property_key(ctx, -1, out_h);
50197}
50198
50199/* String is an own (virtual) property of a lightfunc. */
50200DUK_LOCAL duk_bool_t duk__key_is_lightfunc_ownprop(duk_hthread *thr, duk_hstring *key) {
50201 DUK_UNREF(thr);
50202 return (key == DUK_HTHREAD_STRING_LENGTH(thr) ||
50203 key == DUK_HTHREAD_STRING_NAME(thr));
50204}
50205
50206/* String is an own (virtual) property of a plain buffer. */
50207DUK_LOCAL duk_bool_t duk__key_is_plain_buf_ownprop(duk_hthread *thr, duk_hbuffer *buf, duk_hstring *key, duk_uint32_t arr_idx) {
50208 DUK_UNREF(thr);
50209
50210 /* Virtual index properties. Checking explicitly for
50211 * 'arr_idx != DUK__NO_ARRAY_INDEX' is not necessary
50212 * because DUK__NO_ARRAY_INDEXi is always larger than
50213 * maximum allowed buffer size.
50214 */
50215 DUK_ASSERT(DUK__NO_ARRAY_INDEX >= DUK_HBUFFER_GET_SIZE(buf));
50216 if (arr_idx < DUK_HBUFFER_GET_SIZE(buf)) {
50217 return 1;
50218 }
50219
50220 /* Other virtual properties. */
50221 return (key == DUK_HTHREAD_STRING_LENGTH(thr));
50222}
50223
50224/*
50225 * Helpers for managing property storage size
50226 */
50227
50228/* Get default hash part size for a certain entry part size. */
50229#if defined(DUK_USE_HOBJECT_HASH_PART)
50230DUK_LOCAL duk_uint32_t duk__get_default_h_size(duk_uint32_t e_size) {
50231 DUK_ASSERT(e_size <= DUK_HOBJECT_MAX_PROPERTIES);
50232
50233 if (e_size >= DUK_HOBJECT_E_USE_HASH_LIMIT) {
50234 duk_uint32_t res;
50235
50236 /* result: hash_prime(floor(1.2 * e_size)) */
50237 res = duk_util_get_hash_prime(e_size + e_size / DUK_HOBJECT_H_SIZE_DIVISOR);
50238
50239 /* if fails, e_size will be zero = not an issue, except performance-wise */
50240 DUK_ASSERT(res == 0 || res > e_size);
50241 return res;
50242 } else {
50243 return 0;
50244 }
50245}
50246#endif /* USE_PROP_HASH_PART */
50247
50248/* Get minimum entry part growth for a certain size. */
50249DUK_LOCAL duk_uint32_t duk__get_min_grow_e(duk_uint32_t e_size) {
50250 duk_uint32_t res;
50251
50252 DUK_ASSERT(e_size <= DUK_HOBJECT_MAX_PROPERTIES);
50253
50254 res = (e_size + DUK_HOBJECT_E_MIN_GROW_ADD) / DUK_HOBJECT_E_MIN_GROW_DIVISOR;
50255 DUK_ASSERT(res >= 1); /* important for callers */
50256 return res;
50257}
50258
50259/* Get minimum array part growth for a certain size. */
50260DUK_LOCAL duk_uint32_t duk__get_min_grow_a(duk_uint32_t a_size) {
50261 duk_uint32_t res;
50262
50263 DUK_ASSERT((duk_size_t) a_size <= DUK_HOBJECT_MAX_PROPERTIES);
50264
50265 res = (a_size + DUK_HOBJECT_A_MIN_GROW_ADD) / DUK_HOBJECT_A_MIN_GROW_DIVISOR;
50266 DUK_ASSERT(res >= 1); /* important for callers */
50267 return res;
50268}
50269
50270/* Count actually used entry part entries (non-NULL keys). */
50271DUK_LOCAL duk_uint32_t duk__count_used_e_keys(duk_hthread *thr, duk_hobject *obj) {
50272 duk_uint_fast32_t i;
50273 duk_uint_fast32_t n = 0;
50274 duk_hstring **e;
50275
50276 DUK_ASSERT(obj != NULL);
50277 DUK_UNREF(thr);
50278
50279 e = DUK_HOBJECT_E_GET_KEY_BASE(thr->heap, obj);
50280 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
50281 if (*e++) {
50282 n++;
50283 }
50284 }
50285 return (duk_uint32_t) n;
50286}
50287
50288/* Count actually used array part entries and array minimum size.
50289 * NOTE: 'out_min_size' can be computed much faster by starting from the
50290 * end and breaking out early when finding first used entry, but this is
50291 * not needed now.
50292 */
50293DUK_LOCAL void duk__compute_a_stats(duk_hthread *thr, duk_hobject *obj, duk_uint32_t *out_used, duk_uint32_t *out_min_size) {
50294 duk_uint_fast32_t i;
50295 duk_uint_fast32_t used = 0;
50296 duk_uint_fast32_t highest_idx = (duk_uint_fast32_t) -1; /* see below */
50297 duk_tval *a;
50298
50299 DUK_ASSERT(obj != NULL);
50300 DUK_ASSERT(out_used != NULL);
50301 DUK_ASSERT(out_min_size != NULL);
50302 DUK_UNREF(thr);
50303
50304 a = DUK_HOBJECT_A_GET_BASE(thr->heap, obj);
50305 for (i = 0; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
50306 duk_tval *tv = a++;
50307 if (!DUK_TVAL_IS_UNUSED(tv)) {
50308 used++;
50309 highest_idx = i;
50310 }
50311 }
50312
50313 /* Initial value for highest_idx is -1 coerced to unsigned. This
50314 * is a bit odd, but (highest_idx + 1) will then wrap to 0 below
50315 * for out_min_size as intended.
50316 */
50317
50318 *out_used = used;
50319 *out_min_size = highest_idx + 1; /* 0 if no used entries */
50320}
50321
50322/* Check array density and indicate whether or not the array part should be abandoned. */
50323DUK_LOCAL duk_bool_t duk__abandon_array_density_check(duk_uint32_t a_used, duk_uint32_t a_size) {
50324 /*
50325 * Array abandon check; abandon if:
50326 *
50327 * new_used / new_size < limit
50328 * new_used < limit * new_size || limit is 3 bits fixed point
50329 * new_used < limit' / 8 * new_size || *8
50330 * 8*new_used < limit' * new_size || :8
50331 * new_used < limit' * (new_size / 8)
50332 *
50333 * Here, new_used = a_used, new_size = a_size.
50334 *
50335 * Note: some callers use approximate values for a_used and/or a_size
50336 * (e.g. dropping a '+1' term). This doesn't affect the usefulness
50337 * of the check, but may confuse debugging.
50338 */
50339
50340 return (a_used < DUK_HOBJECT_A_ABANDON_LIMIT * (a_size >> 3));
50341}
50342
50343/* Fast check for extending array: check whether or not a slow density check is required. */
50344DUK_LOCAL duk_bool_t duk__abandon_array_slow_check_required(duk_uint32_t arr_idx, duk_uint32_t old_size) {
50345 /*
50346 * In a fast check we assume old_size equals old_used (i.e., existing
50347 * array is fully dense).
50348 *
50349 * Slow check if:
50350 *
50351 * (new_size - old_size) / old_size > limit
50352 * new_size - old_size > limit * old_size
50353 * new_size > (1 + limit) * old_size || limit' is 3 bits fixed point
50354 * new_size > (1 + (limit' / 8)) * old_size || * 8
50355 * 8 * new_size > (8 + limit') * old_size || : 8
50356 * new_size > (8 + limit') * (old_size / 8)
50357 * new_size > limit'' * (old_size / 8) || limit'' = 9 -> max 25% increase
50358 * arr_idx + 1 > limit'' * (old_size / 8)
50359 *
50360 * This check doesn't work well for small values, so old_size is rounded
50361 * up for the check (and the '+ 1' of arr_idx can be ignored in practice):
50362 *
50363 * arr_idx > limit'' * ((old_size + 7) / 8)
50364 */
50365
50366 return (arr_idx > DUK_HOBJECT_A_FAST_RESIZE_LIMIT * ((old_size + 7) >> 3));
50367}
50368
50369/*
50370 * Proxy helpers
50371 */
50372
50373#if defined(DUK_USE_ES6_PROXY)
50374DUK_INTERNAL duk_bool_t duk_hobject_proxy_check(duk_hthread *thr, duk_hobject *obj, duk_hobject **out_target, duk_hobject **out_handler) {
50375 duk_tval *tv_target;
50376 duk_tval *tv_handler;
50377 duk_hobject *h_target;
50378 duk_hobject *h_handler;
50379
50380 DUK_ASSERT(thr != NULL);
50381 DUK_ASSERT(obj != NULL);
50382 DUK_ASSERT(out_target != NULL);
50383 DUK_ASSERT(out_handler != NULL);
50384
50385 /* Caller doesn't need to check exotic proxy behavior (but does so for
50386 * some fast paths).
50387 */
50388 if (DUK_LIKELY(!DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
50389 return 0;
50390 }
50391
50392 tv_handler = duk_hobject_find_existing_entry_tval_ptr(thr->heap, obj, DUK_HTHREAD_STRING_INT_HANDLER(thr));
50393 if (!tv_handler) {
50394 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REVOKED);
50395 return 0;
50396 }
50397 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_handler));
50398 h_handler = DUK_TVAL_GET_OBJECT(tv_handler);
50399 DUK_ASSERT(h_handler != NULL);
50400 *out_handler = h_handler;
50401 tv_handler = NULL; /* avoid issues with relocation */
50402
50403 tv_target = duk_hobject_find_existing_entry_tval_ptr(thr->heap, obj, DUK_HTHREAD_STRING_INT_TARGET(thr));
50404 if (!tv_target) {
50405 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REVOKED);
50406 return 0;
50407 }
50408 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_target));
50409 h_target = DUK_TVAL_GET_OBJECT(tv_target);
50410 DUK_ASSERT(h_target != NULL);
50411 *out_target = h_target;
50412 tv_target = NULL; /* avoid issues with relocation */
50413
50414 return 1;
50415}
50416#endif /* DUK_USE_ES6_PROXY */
50417
50418/* Get Proxy target object. If the argument is not a Proxy, return it as is.
50419 * If a Proxy is revoked, an error is thrown.
50420 */
50421#if defined(DUK_USE_ES6_PROXY)
50422DUK_INTERNAL duk_hobject *duk_hobject_resolve_proxy_target(duk_hthread *thr, duk_hobject *obj) {
50423 duk_hobject *h_target;
50424 duk_hobject *h_handler;
50425
50426 DUK_ASSERT(thr != NULL);
50427 DUK_ASSERT(obj != NULL);
50428
50429 /* Resolve Proxy targets until Proxy chain ends. No explicit check for
50430 * a Proxy loop: user code cannot create such a loop without tweaking
50431 * internal properties directly.
50432 */
50433
50434 while (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
50435 if (duk_hobject_proxy_check(thr, obj, &h_target, &h_handler)) {
50436 DUK_ASSERT(h_target != NULL);
50437 obj = h_target;
50438 } else {
50439 break;
50440 }
50441 }
50442
50443 DUK_ASSERT(obj != NULL);
50444 return obj;
50445}
50446#endif /* DUK_USE_ES6_PROXY */
50447
50448#if defined(DUK_USE_ES6_PROXY)
50449DUK_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) {
50450 duk_context *ctx = (duk_context *) thr;
50451 duk_hobject *h_handler;
50452
50453 DUK_ASSERT(thr != NULL);
50454 DUK_ASSERT(obj != NULL);
50455 DUK_ASSERT(tv_key != NULL);
50456 DUK_ASSERT(out_target != NULL);
50457
50458 if (!duk_hobject_proxy_check(thr, obj, out_target, &h_handler)) {
50459 return 0;
50460 }
50461 DUK_ASSERT(*out_target != NULL);
50462 DUK_ASSERT(h_handler != NULL);
50463
50464 /* XXX: At the moment Duktape accesses internal keys like _Finalizer using a
50465 * normal property set/get which would allow a proxy handler to interfere with
50466 * such behavior and to get access to internal key strings. This is not a problem
50467 * as such because internal key strings can be created in other ways too (e.g.
50468 * through buffers). The best fix is to change Duktape internal lookups to
50469 * skip proxy behavior. Until that, internal property accesses bypass the
50470 * proxy and are applied to the target (as if the handler did not exist).
50471 * This has some side effects, see test-bi-proxy-internal-keys.js.
50472 */
50473
50474 if (DUK_TVAL_IS_STRING(tv_key)) {
50475 duk_hstring *h_key = (duk_hstring *) DUK_TVAL_GET_STRING(tv_key);
50476 DUK_ASSERT(h_key != NULL);
50477 if (DUK_HSTRING_HAS_HIDDEN(h_key)) {
50478 /* Symbol accesses must go through proxy lookup in ES2015.
50479 * Hidden symbols behave like Duktape 1.x internal keys
50480 * and currently won't.
50481 */
50482 DUK_DDD(DUK_DDDPRINT("hidden key, skip proxy handler and apply to target"));
50483 return 0;
50484 }
50485 }
50486
50487 /* The handler is looked up with a normal property lookup; it may be an
50488 * accessor or the handler object itself may be a proxy object. If the
50489 * handler is a proxy, we need to extend the valstack as we make a
50490 * recursive proxy check without a function call in between (in fact
50491 * there is no limit to the potential recursion here).
50492 *
50493 * (For sanity, proxy creation rejects another proxy object as either
50494 * the handler or the target at the moment so recursive proxy cases
50495 * are not realized now.)
50496 */
50497
50498 /* XXX: C recursion limit if proxies are allowed as handler/target values */
50499
50500 duk_require_stack(ctx, DUK__VALSTACK_PROXY_LOOKUP);
50501 duk_push_hobject(ctx, h_handler);
50502 if (duk_get_prop_stridx_short(ctx, -1, stridx_trap)) {
50503 /* -> [ ... handler trap ] */
50504 duk_insert(ctx, -2); /* -> [ ... trap handler ] */
50505
50506 /* stack prepped for func call: [ ... trap handler ] */
50507 return 1;
50508 } else {
50509 duk_pop_2(ctx);
50510 return 0;
50511 }
50512}
50513#endif /* DUK_USE_ES6_PROXY */
50514
50515/*
50516 * Reallocate property allocation, moving properties to the new allocation.
50517 *
50518 * Includes key compaction, rehashing, and can also optionally abandoning
50519 * the array part, 'migrating' array entries into the beginning of the
50520 * new entry part. Arguments are not validated here, so e.g. new_h_size
50521 * MUST be a valid prime.
50522 *
50523 * There is no support for in-place reallocation or just compacting keys
50524 * without resizing the property allocation. This is intentional to keep
50525 * code size minimal.
50526 *
50527 * The implementation is relatively straightforward, except for the array
50528 * abandonment process. Array abandonment requires that new string keys
50529 * are interned, which may trigger GC. All keys interned so far must be
50530 * reachable for GC at all times; valstack is used for that now.
50531 *
50532 * Also, a GC triggered during this reallocation process must not interfere
50533 * with the object being resized. This is currently controlled by using
50534 * heap->mark_and_sweep_base_flags to indicate that no finalizers will be
50535 * executed (as they can affect ANY object) and no objects are compacted
50536 * (it would suffice to protect this particular object only, though).
50537 *
50538 * Note: a non-checked variant would be nice but is a bit tricky to
50539 * implement for the array abandonment process. It's easy for
50540 * everything else.
50541 *
50542 * Note: because we need to potentially resize the valstack (as part
50543 * of abandoning the array part), any tval pointers to the valstack
50544 * will become invalid after this call.
50545 */
50546
50547DUK_INTERNAL void duk_hobject_realloc_props(duk_hthread *thr,
50548 duk_hobject *obj,
50549 duk_uint32_t new_e_size,
50550 duk_uint32_t new_a_size,
50551 duk_uint32_t new_h_size,
50552 duk_bool_t abandon_array) {
50553 duk_context *ctx = (duk_context *) thr;
50554 duk_small_uint_t prev_mark_and_sweep_base_flags;
50555 duk_uint32_t new_alloc_size;
50556 duk_uint32_t new_e_size_adjusted;
50557 duk_uint8_t *new_p;
50558 duk_hstring **new_e_k;
50559 duk_propvalue *new_e_pv;
50560 duk_uint8_t *new_e_f;
50561 duk_tval *new_a;
50562 duk_uint32_t *new_h;
50563 duk_uint32_t new_e_next;
50564 duk_uint_fast32_t i;
50565
50566 DUK_ASSERT(thr != NULL);
50567 DUK_ASSERT(ctx != NULL);
50568 DUK_ASSERT(obj != NULL);
50569 DUK_ASSERT(!abandon_array || new_a_size == 0); /* if abandon_array, new_a_size must be 0 */
50570 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL || (DUK_HOBJECT_GET_ESIZE(obj) == 0 && DUK_HOBJECT_GET_ASIZE(obj) == 0));
50571 DUK_ASSERT(new_h_size == 0 || new_h_size >= new_e_size); /* required to guarantee success of rehashing,
50572 * intentionally use unadjusted new_e_size
50573 */
50574 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
50575 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
50576
50577 /*
50578 * Pre resize assertions.
50579 */
50580
50581#if defined(DUK_USE_ASSERTIONS)
50582 /* XXX: pre-checks (such as no duplicate keys) */
50583#endif
50584
50585 /*
50586 * For property layout 1, tweak e_size to ensure that the whole entry
50587 * part (key + val + flags) is a suitable multiple for alignment
50588 * (platform specific).
50589 *
50590 * Property layout 2 does not require this tweaking and is preferred
50591 * on low RAM platforms requiring alignment.
50592 */
50593
50594#if defined(DUK_USE_HOBJECT_LAYOUT_2) || defined(DUK_USE_HOBJECT_LAYOUT_3)
50595 DUK_DDD(DUK_DDDPRINT("using layout 2 or 3, no need to pad e_size: %ld", (long) new_e_size));
50596 new_e_size_adjusted = new_e_size;
50597#elif defined(DUK_USE_HOBJECT_LAYOUT_1) && (DUK_HOBJECT_ALIGN_TARGET == 1)
50598 DUK_DDD(DUK_DDDPRINT("using layout 1, but no need to pad e_size: %ld", (long) new_e_size));
50599 new_e_size_adjusted = new_e_size;
50600#elif defined(DUK_USE_HOBJECT_LAYOUT_1) && ((DUK_HOBJECT_ALIGN_TARGET == 4) || (DUK_HOBJECT_ALIGN_TARGET == 8))
50601 new_e_size_adjusted = (new_e_size + DUK_HOBJECT_ALIGN_TARGET - 1) & (~(DUK_HOBJECT_ALIGN_TARGET - 1));
50602 DUK_DDD(DUK_DDDPRINT("using layout 1, and alignment target is %ld, adjusted e_size: %ld -> %ld",
50603 (long) DUK_HOBJECT_ALIGN_TARGET, (long) new_e_size, (long) new_e_size_adjusted));
50604 DUK_ASSERT(new_e_size_adjusted >= new_e_size);
50605#else
50606#error invalid hobject layout defines
50607#endif
50608
50609 /*
50610 * Debug logging after adjustment.
50611 */
50612
50613 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 "
50614 "{e_size=%ld,a_size=%ld,h_size=%ld}, abandon_array=%ld, unadjusted new_e_size=%ld",
50615 (void *) obj,
50616 (long) DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj),
50617 DUK_HOBJECT_GET_ASIZE(obj),
50618 DUK_HOBJECT_GET_HSIZE(obj)),
50619 (long) DUK_HOBJECT_P_COMPUTE_SIZE(new_e_size_adjusted, new_a_size, new_h_size),
50620 (void *) DUK_HOBJECT_GET_PROPS(thr->heap, obj),
50621 (long) DUK_HOBJECT_GET_ESIZE(obj),
50622 (long) DUK_HOBJECT_GET_ENEXT(obj),
50623 (long) DUK_HOBJECT_GET_ASIZE(obj),
50624 (long) DUK_HOBJECT_GET_HSIZE(obj),
50625 (long) new_e_size_adjusted,
50626 (long) new_a_size,
50627 (long) new_h_size,
50628 (long) abandon_array,
50629 (long) new_e_size));
50630
50631 /*
50632 * Property count check. This is the only point where we ensure that
50633 * we don't get more (allocated) property space that we can handle.
50634 * There aren't hard limits as such, but some algorithms fail (e.g.
50635 * finding next higher prime, selecting hash part size) if we get too
50636 * close to the 4G property limit.
50637 *
50638 * Since this works based on allocation size (not actually used size),
50639 * the limit is a bit approximate but good enough in practice.
50640 */
50641
50642 if (new_e_size_adjusted + new_a_size > DUK_HOBJECT_MAX_PROPERTIES) {
50643 DUK_ERROR_ALLOC_FAILED(thr);
50644 }
50645
50646 /*
50647 * Compute new alloc size and alloc new area.
50648 *
50649 * The new area is allocated as a dynamic buffer and placed into the
50650 * valstack for reachability. The actual buffer is then detached at
50651 * the end.
50652 *
50653 * Note: heap_mark_and_sweep_base_flags are altered here to ensure
50654 * no-one touches this object while we're resizing and rehashing it.
50655 * The flags must be reset on every exit path after it. Finalizers
50656 * and compaction is prevented currently for all objects while it
50657 * would be enough to restrict it only for the current object.
50658 */
50659
50660 prev_mark_and_sweep_base_flags = thr->heap->mark_and_sweep_base_flags;
50661 thr->heap->mark_and_sweep_base_flags |=
50662 DUK_MS_FLAG_NO_FINALIZERS | /* avoid attempts to add/remove object keys */
50663 DUK_MS_FLAG_NO_OBJECT_COMPACTION; /* avoid attempt to compact the current object */
50664
50665 new_alloc_size = DUK_HOBJECT_P_COMPUTE_SIZE(new_e_size_adjusted, new_a_size, new_h_size);
50666 DUK_DDD(DUK_DDDPRINT("new hobject allocation size is %ld", (long) new_alloc_size));
50667 if (new_alloc_size == 0) {
50668 /* for zero size, don't push anything on valstack */
50669 DUK_ASSERT(new_e_size_adjusted == 0);
50670 DUK_ASSERT(new_a_size == 0);
50671 DUK_ASSERT(new_h_size == 0);
50672 new_p = NULL;
50673 } else {
50674 /* This may trigger mark-and-sweep with arbitrary side effects,
50675 * including an attempted resize of the object we're resizing,
50676 * executing a finalizer which may add or remove properties of
50677 * the object we're resizing etc.
50678 */
50679
50680 /* Note: buffer is dynamic so that we can 'steal' the actual
50681 * allocation later.
50682 */
50683
50684 new_p = (duk_uint8_t *) duk_push_dynamic_buffer(ctx, new_alloc_size); /* errors out if out of memory */
50685 DUK_ASSERT(new_p != NULL); /* since new_alloc_size > 0 */
50686 }
50687
50688 /* Set up pointers to the new property area: this is hidden behind a macro
50689 * because it is memory layout specific.
50690 */
50691 DUK_HOBJECT_P_SET_REALLOC_PTRS(new_p, new_e_k, new_e_pv, new_e_f, new_a, new_h,
50692 new_e_size_adjusted, new_a_size, new_h_size);
50693 DUK_UNREF(new_h); /* happens when hash part dropped */
50694 new_e_next = 0;
50695
50696 /* if new_p == NULL, all of these pointers are NULL */
50697 DUK_ASSERT((new_p != NULL) ||
50698 (new_e_k == NULL && new_e_pv == NULL && new_e_f == NULL &&
50699 new_a == NULL && new_h == NULL));
50700
50701 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",
50702 (long) new_alloc_size, (void *) new_e_k, (void *) new_e_pv, (void *) new_e_f,
50703 (void *) new_a, (void *) new_h));
50704
50705 /*
50706 * Migrate array to start of entries if requested.
50707 *
50708 * Note: from an enumeration perspective the order of entry keys matters.
50709 * Array keys should appear wherever they appeared before the array abandon
50710 * operation.
50711 */
50712
50713 if (abandon_array) {
50714 /*
50715 * Note: assuming new_a_size == 0, and that entry part contains
50716 * no conflicting keys, refcounts do not need to be adjusted for
50717 * the values, as they remain exactly the same.
50718 *
50719 * The keys, however, need to be interned, incref'd, and be
50720 * reachable for GC. Any intern attempt may trigger a GC and
50721 * claim any non-reachable strings, so every key must be reachable
50722 * at all times.
50723 *
50724 * A longjmp must not occur here, as the new_p allocation would
50725 * be freed without these keys being decref'd, hence the messy
50726 * decref handling if intern fails.
50727 */
50728 DUK_ASSERT(new_a_size == 0);
50729
50730 for (i = 0; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
50731 duk_tval *tv1;
50732 duk_tval *tv2;
50734
50735 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
50736
50737 tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i);
50738 if (DUK_TVAL_IS_UNUSED(tv1)) {
50739 continue;
50740 }
50741
50742 DUK_ASSERT(new_p != NULL && new_e_k != NULL &&
50743 new_e_pv != NULL && new_e_f != NULL);
50744
50745 /*
50746 * Intern key via the valstack to ensure reachability behaves
50747 * properly. We must avoid longjmp's here so use non-checked
50748 * primitives.
50749 *
50750 * Note: duk_check_stack() potentially reallocs the valstack,
50751 * invalidating any duk_tval pointers to valstack. Callers
50752 * must be careful.
50753 */
50754
50755 /* never shrinks; auto-adds DUK_VALSTACK_INTERNAL_EXTRA, which is generous */
50756 if (!duk_check_stack(ctx, 1)) {
50757 goto abandon_error;
50758 }
50759 DUK_ASSERT_VALSTACK_SPACE(thr, 1);
50760 key = duk_heap_string_intern_u32(thr->heap, i);
50761 if (!key) {
50762 goto abandon_error;
50763 }
50764 duk_push_hstring(ctx, key); /* keep key reachable for GC etc; guaranteed not to fail */
50765
50766 /* key is now reachable in the valstack */
50767
50768 DUK_HSTRING_INCREF(thr, key); /* second incref for the entry reference */
50769 new_e_k[new_e_next] = key;
50770 tv2 = &new_e_pv[new_e_next].v; /* array entries are all plain values */
50771 DUK_TVAL_SET_TVAL(tv2, tv1);
50772 new_e_f[new_e_next] = DUK_PROPDESC_FLAG_WRITABLE |
50773 DUK_PROPDESC_FLAG_ENUMERABLE |
50774 DUK_PROPDESC_FLAG_CONFIGURABLE;
50775 new_e_next++;
50776
50777 /* Note: new_e_next matches pushed temp key count, and nothing can
50778 * fail above between the push and this point.
50779 */
50780 }
50781
50782 DUK_DDD(DUK_DDDPRINT("abandon array: pop %ld key temps from valstack", (long) new_e_next));
50783 duk_pop_n(ctx, new_e_next);
50784 }
50785
50786 /*
50787 * Copy keys and values in the entry part (compacting them at the same time).
50788 */
50789
50790 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
50792
50793 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
50794
50795 key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i);
50796 if (!key) {
50797 continue;
50798 }
50799
50800 DUK_ASSERT(new_p != NULL && new_e_k != NULL &&
50801 new_e_pv != NULL && new_e_f != NULL);
50802
50803 new_e_k[new_e_next] = key;
50804 new_e_pv[new_e_next] = DUK_HOBJECT_E_GET_VALUE(thr->heap, obj, i);
50805 new_e_f[new_e_next] = DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, i);
50806 new_e_next++;
50807 }
50808 /* the entries [new_e_next, new_e_size_adjusted[ are left uninitialized on purpose (ok, not gc reachable) */
50809
50810 /*
50811 * Copy array elements to new array part.
50812 */
50813
50814 if (new_a_size > DUK_HOBJECT_GET_ASIZE(obj)) {
50815 /* copy existing entries as is */
50816 DUK_ASSERT(new_p != NULL && new_a != NULL);
50817 if (DUK_HOBJECT_GET_ASIZE(obj) > 0) {
50818 /* Avoid zero copy with an invalid pointer. If obj->p is NULL,
50819 * the 'new_a' pointer will be invalid which is not allowed even
50820 * when copy size is zero.
50821 */
50822 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
50823 DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) > 0);
50824 DUK_MEMCPY((void *) new_a, (void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj), sizeof(duk_tval) * DUK_HOBJECT_GET_ASIZE(obj));
50825 }
50826
50827 /* fill new entries with -unused- (required, gc reachable) */
50828 for (i = DUK_HOBJECT_GET_ASIZE(obj); i < new_a_size; i++) {
50829 duk_tval *tv = &new_a[i];
50830 DUK_TVAL_SET_UNUSED(tv);
50831 }
50832 } else {
50833#if defined(DUK_USE_ASSERTIONS)
50834 /* caller must have decref'd values above new_a_size (if that is necessary) */
50835 if (!abandon_array) {
50836 for (i = new_a_size; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
50837 duk_tval *tv;
50838 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i);
50839
50840 /* current assertion is quite strong: decref's and set to unused */
50841 DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv));
50842 }
50843 }
50844#endif
50845 if (new_a_size > 0) {
50846 /* Avoid zero copy with an invalid pointer. If obj->p is NULL,
50847 * the 'new_a' pointer will be invalid which is not allowed even
50848 * when copy size is zero.
50849 */
50850 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
50851 DUK_ASSERT(new_a_size > 0);
50852 DUK_MEMCPY((void *) new_a, (void *) DUK_HOBJECT_A_GET_BASE(thr->heap, obj), sizeof(duk_tval) * new_a_size);
50853 }
50854 }
50855
50856 /*
50857 * Rebuild the hash part always from scratch (guaranteed to finish).
50858 *
50859 * Any resize of hash part requires rehashing. In addition, by rehashing
50860 * get rid of any elements marked deleted (DUK__HASH_DELETED) which is critical
50861 * to ensuring the hash part never fills up.
50862 */
50863
50864#if defined(DUK_USE_HOBJECT_HASH_PART)
50865 if (DUK_UNLIKELY(new_h_size > 0)) {
50866 DUK_ASSERT(new_h != NULL);
50867
50868 /* fill new_h with u32 0xff = UNUSED */
50869 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, obj) != NULL);
50870 DUK_ASSERT(new_h_size > 0);
50871 DUK_MEMSET(new_h, 0xff, sizeof(duk_uint32_t) * new_h_size);
50872
50873 DUK_ASSERT(new_e_next <= new_h_size); /* equality not actually possible */
50874 for (i = 0; i < new_e_next; i++) {
50875 duk_hstring *key = new_e_k[i];
50876 duk_uint32_t j, step;
50877
50878 DUK_ASSERT(key != NULL);
50879 j = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), new_h_size);
50880 step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key));
50881
50882 for (;;) {
50883 DUK_ASSERT(new_h[j] != DUK__HASH_DELETED); /* should never happen */
50884 if (new_h[j] == DUK__HASH_UNUSED) {
50885 DUK_DDD(DUK_DDDPRINT("rebuild hit %ld -> %ld", (long) j, (long) i));
50886 new_h[j] = i;
50887 break;
50888 }
50889 DUK_DDD(DUK_DDDPRINT("rebuild miss %ld, step %ld", (long) j, (long) step));
50890 j = (j + step) % new_h_size;
50891
50892 /* guaranteed to finish */
50893 DUK_ASSERT(j != (duk_uint32_t) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), new_h_size));
50894 }
50895 }
50896 } else {
50897 DUK_DDD(DUK_DDDPRINT("no hash part, no rehash"));
50898 }
50899#endif /* DUK_USE_HOBJECT_HASH_PART */
50900
50901 /*
50902 * Nice debug log.
50903 */
50904
50905 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 "
50906 "{p=%p,e_size=%ld,e_next=%ld,a_size=%ld,h_size=%ld}, abandon_array=%ld, unadjusted new_e_size=%ld",
50907 (void *) obj,
50908 (long) DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj),
50909 DUK_HOBJECT_GET_ASIZE(obj),
50910 DUK_HOBJECT_GET_HSIZE(obj)),
50911 (long) new_alloc_size,
50912 (void *) DUK_HOBJECT_GET_PROPS(thr->heap, obj),
50913 (long) DUK_HOBJECT_GET_ESIZE(obj),
50914 (long) DUK_HOBJECT_GET_ENEXT(obj),
50915 (long) DUK_HOBJECT_GET_ASIZE(obj),
50916 (long) DUK_HOBJECT_GET_HSIZE(obj),
50917 (void *) new_p,
50918 (long) new_e_size_adjusted,
50919 (long) new_e_next,
50920 (long) new_a_size,
50921 (long) new_h_size,
50922 (long) abandon_array,
50923 (long) new_e_size));
50924
50925 /*
50926 * All done, switch properties ('p') allocation to new one.
50927 */
50928
50929 DUK_FREE(thr->heap, DUK_HOBJECT_GET_PROPS(thr->heap, obj)); /* NULL obj->p is OK */
50930 DUK_HOBJECT_SET_PROPS(thr->heap, obj, new_p);
50931 DUK_HOBJECT_SET_ESIZE(obj, new_e_size_adjusted);
50932 DUK_HOBJECT_SET_ENEXT(obj, new_e_next);
50933 DUK_HOBJECT_SET_ASIZE(obj, new_a_size);
50934 DUK_HOBJECT_SET_HSIZE(obj, new_h_size);
50935
50936 if (new_p) {
50937 /*
50938 * Detach actual buffer from dynamic buffer in valstack, and
50939 * pop it from the stack.
50940 *
50941 * XXX: the buffer object is certainly not reachable at this point,
50942 * so it would be nice to free it forcibly even with only
50943 * mark-and-sweep enabled. Not a big issue though.
50944 */
50945 (void) duk_steal_buffer(ctx, -1, NULL);
50946 duk_pop(ctx);
50947 } else {
50948 DUK_ASSERT(new_alloc_size == 0);
50949 /* no need to pop, nothing was pushed */
50950 }
50951
50952 /* clear array part flag only after switching */
50953 if (abandon_array) {
50954 DUK_HOBJECT_CLEAR_ARRAY_PART(obj);
50955 }
50956
50957 DUK_DDD(DUK_DDDPRINT("resize result: %!O", (duk_heaphdr *) obj));
50958
50959 thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
50960
50961 /*
50962 * Post resize assertions.
50963 */
50964
50965#if defined(DUK_USE_ASSERTIONS)
50966 /* XXX: post-checks (such as no duplicate keys) */
50967#endif
50968 return;
50969
50970 /*
50971 * Abandon array failed, need to decref keys already inserted
50972 * into the beginning of new_e_k before unwinding valstack.
50973 */
50974
50975 abandon_error:
50976 DUK_D(DUK_DPRINT("hobject resize failed during abandon array, decref keys"));
50977 i = new_e_next;
50978 while (i > 0) {
50979 i--;
50980 DUK_ASSERT(new_e_k != NULL);
50981 DUK_ASSERT(new_e_k[i] != NULL);
50982 DUK_HSTRING_DECREF(thr, new_e_k[i]); /* side effects */
50983 }
50984
50985 thr->heap->mark_and_sweep_base_flags = prev_mark_and_sweep_base_flags;
50986
50987 DUK_ERROR_ALLOC_FAILED(thr);
50988}
50989
50990/*
50991 * Helpers to resize properties allocation on specific needs.
50992 */
50993
50994/* Grow entry part allocation for one additional entry. */
50995DUK_LOCAL void duk__grow_props_for_new_entry_item(duk_hthread *thr, duk_hobject *obj) {
50996 duk_uint32_t old_e_used; /* actually used, non-NULL entries */
50997 duk_uint32_t new_e_size;
50998 duk_uint32_t new_a_size;
50999 duk_uint32_t new_h_size;
51000
51001 DUK_ASSERT(thr != NULL);
51002 DUK_ASSERT(obj != NULL);
51003
51004 /* Duktape 0.11.0 and prior tried to optimize the resize by not
51005 * counting the number of actually used keys prior to the resize.
51006 * This worked mostly well but also caused weird leak-like behavior
51007 * as in: test-bug-object-prop-alloc-unbounded.js. So, now we count
51008 * the keys explicitly to compute the new entry part size.
51009 */
51010
51011 old_e_used = duk__count_used_e_keys(thr, obj);
51012 new_e_size = old_e_used + duk__get_min_grow_e(old_e_used);
51013#if defined(DUK_USE_HOBJECT_HASH_PART)
51014 new_h_size = duk__get_default_h_size(new_e_size);
51015#else
51016 new_h_size = 0;
51017#endif
51018 new_a_size = DUK_HOBJECT_GET_ASIZE(obj);
51019 DUK_ASSERT(new_e_size >= old_e_used + 1); /* duk__get_min_grow_e() is always >= 1 */
51020
51021 duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0);
51022}
51023
51024/* Grow array part for a new highest array index. */
51025DUK_LOCAL void duk__grow_props_for_array_item(duk_hthread *thr, duk_hobject *obj, duk_uint32_t highest_arr_idx) {
51026 duk_uint32_t new_e_size;
51027 duk_uint32_t new_a_size;
51028 duk_uint32_t new_h_size;
51029
51030 DUK_ASSERT(thr != NULL);
51031 DUK_ASSERT(obj != NULL);
51032 DUK_ASSERT(highest_arr_idx >= DUK_HOBJECT_GET_ASIZE(obj));
51033
51034 /* minimum new length is highest_arr_idx + 1 */
51035
51036 new_e_size = DUK_HOBJECT_GET_ESIZE(obj);
51037 new_h_size = DUK_HOBJECT_GET_HSIZE(obj);
51038 new_a_size = highest_arr_idx + duk__get_min_grow_a(highest_arr_idx);
51039 DUK_ASSERT(new_a_size >= highest_arr_idx + 1); /* duk__get_min_grow_a() is always >= 1 */
51040
51041 duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 0);
51042}
51043
51044/* Abandon array part, moving array entries into entries part.
51045 * This requires a props resize, which is a heavy operation.
51046 * We also compact the entries part while we're at it, although
51047 * this is not strictly required.
51048 */
51049DUK_LOCAL void duk__abandon_array_checked(duk_hthread *thr, duk_hobject *obj) {
51050 duk_uint32_t new_e_size;
51051 duk_uint32_t new_a_size;
51052 duk_uint32_t new_h_size;
51053 duk_uint32_t e_used; /* actually used, non-NULL keys */
51054 duk_uint32_t a_used;
51055 duk_uint32_t a_size;
51056
51057 DUK_ASSERT(thr != NULL);
51058 DUK_ASSERT(obj != NULL);
51059
51060 e_used = duk__count_used_e_keys(thr, obj);
51061 duk__compute_a_stats(thr, obj, &a_used, &a_size);
51062
51063 /*
51064 * Must guarantee all actually used array entries will fit into
51065 * new entry part. Add one growth step to ensure we don't run out
51066 * of space right away.
51067 */
51068
51069 new_e_size = e_used + a_used;
51070 new_e_size = new_e_size + duk__get_min_grow_e(new_e_size);
51071 new_a_size = 0;
51072#if defined(DUK_USE_HOBJECT_HASH_PART)
51073 new_h_size = duk__get_default_h_size(new_e_size);
51074#else
51075 new_h_size = 0;
51076#endif
51077
51078 DUK_DD(DUK_DDPRINT("abandon array part for hobject %p, "
51079 "array stats before: e_used=%ld, a_used=%ld, a_size=%ld; "
51080 "resize to e_size=%ld, a_size=%ld, h_size=%ld",
51081 (void *) obj, (long) e_used, (long) a_used, (long) a_size,
51082 (long) new_e_size, (long) new_a_size, (long) new_h_size));
51083
51084 duk_hobject_realloc_props(thr, obj, new_e_size, new_a_size, new_h_size, 1);
51085}
51086
51087/*
51088 * Compact an object. Minimizes allocation size for objects which are
51089 * not likely to be extended. This is useful for internal and non-
51090 * extensible objects, but can also be called for non-extensible objects.
51091 * May abandon the array part if it is computed to be too sparse.
51092 *
51093 * This call is relatively expensive, as it needs to scan both the
51094 * entries and the array part.
51095 *
51096 * The call may fail due to allocation error.
51097 */
51098
51099DUK_INTERNAL void duk_hobject_compact_props(duk_hthread *thr, duk_hobject *obj) {
51100 duk_uint32_t e_size; /* currently used -> new size */
51101 duk_uint32_t a_size; /* currently required */
51102 duk_uint32_t a_used; /* actually used */
51103 duk_uint32_t h_size;
51104 duk_bool_t abandon_array;
51105
51106 DUK_ASSERT(thr != NULL);
51107 DUK_ASSERT(obj != NULL);
51108
51109#if defined(DUK_USE_ROM_OBJECTS)
51110 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
51111 DUK_DD(DUK_DDPRINT("ignore attempt to compact a rom object"));
51112 return;
51113 }
51114#endif
51115
51116 e_size = duk__count_used_e_keys(thr, obj);
51117 duk__compute_a_stats(thr, obj, &a_used, &a_size);
51118
51119 DUK_DD(DUK_DDPRINT("compacting hobject, used e keys %ld, used a keys %ld, min a size %ld, "
51120 "resized array density would be: %ld/%ld = %lf",
51121 (long) e_size, (long) a_used, (long) a_size,
51122 (long) a_used, (long) a_size,
51123 (double) a_used / (double) a_size));
51124
51125 if (duk__abandon_array_density_check(a_used, a_size)) {
51126 DUK_DD(DUK_DDPRINT("decided to abandon array during compaction, a_used=%ld, a_size=%ld",
51127 (long) a_used, (long) a_size));
51128 abandon_array = 1;
51129 e_size += a_used;
51130 a_size = 0;
51131 } else {
51132 DUK_DD(DUK_DDPRINT("decided to keep array during compaction"));
51133 abandon_array = 0;
51134 }
51135
51136#if defined(DUK_USE_HOBJECT_HASH_PART)
51137 if (e_size >= DUK_HOBJECT_E_USE_HASH_LIMIT) {
51138 h_size = duk__get_default_h_size(e_size);
51139 } else {
51140 h_size = 0;
51141 }
51142#else
51143 h_size = 0;
51144#endif
51145
51146 DUK_DD(DUK_DDPRINT("compacting hobject -> new e_size %ld, new a_size=%ld, new h_size=%ld, abandon_array=%ld",
51147 (long) e_size, (long) a_size, (long) h_size, (long) abandon_array));
51148
51149 duk_hobject_realloc_props(thr, obj, e_size, a_size, h_size, abandon_array);
51150}
51151
51152/*
51153 * Find an existing key from entry part either by linear scan or by
51154 * using the hash index (if it exists).
51155 *
51156 * Sets entry index (and possibly the hash index) to output variables,
51157 * which allows the caller to update the entry and hash entries in-place.
51158 * If entry is not found, both values are set to -1. If entry is found
51159 * but there is no hash part, h_idx is set to -1.
51160 */
51161
51162DUK_INTERNAL void duk_hobject_find_existing_entry(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *e_idx, duk_int_t *h_idx) {
51163 DUK_ASSERT(obj != NULL);
51164 DUK_ASSERT(key != NULL);
51165 DUK_ASSERT(e_idx != NULL);
51166 DUK_ASSERT(h_idx != NULL);
51167 DUK_UNREF(heap);
51168
51169 if (DUK_LIKELY(DUK_HOBJECT_GET_HSIZE(obj) == 0))
51170 {
51171 /* Linear scan: more likely because most objects are small.
51172 * This is an important fast path.
51173 *
51174 * XXX: this might be worth inlining for property lookups.
51175 */
51176 duk_uint_fast32_t i;
51177 duk_uint_fast32_t n;
51178 duk_hstring **h_keys_base;
51179 DUK_DDD(DUK_DDDPRINT("duk_hobject_find_existing_entry() using linear scan for lookup"));
51180
51181 h_keys_base = DUK_HOBJECT_E_GET_KEY_BASE(heap, obj);
51182 n = DUK_HOBJECT_GET_ENEXT(obj);
51183 for (i = 0; i < n; i++) {
51184 if (h_keys_base[i] == key) {
51185 *e_idx = i;
51186 *h_idx = -1;
51187 return;
51188 }
51189 }
51190 }
51191#if defined(DUK_USE_HOBJECT_HASH_PART)
51192 else
51193 {
51194 /* hash lookup */
51195 duk_uint32_t n;
51196 duk_uint32_t i, step;
51197 duk_uint32_t *h_base;
51198
51199 DUK_DDD(DUK_DDDPRINT("duk_hobject_find_existing_entry() using hash part for lookup"));
51200
51201 h_base = DUK_HOBJECT_H_GET_BASE(heap, obj);
51202 n = DUK_HOBJECT_GET_HSIZE(obj);
51203 i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n);
51204 step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key));
51205
51206 for (;;) {
51207 duk_uint32_t t;
51208
51209 DUK_ASSERT_DISABLE(i >= 0); /* unsigned */
51210 DUK_ASSERT(i < DUK_HOBJECT_GET_HSIZE(obj));
51211 t = h_base[i];
51212 DUK_ASSERT(t == DUK__HASH_UNUSED || t == DUK__HASH_DELETED ||
51213 (t < DUK_HOBJECT_GET_ESIZE(obj))); /* t >= 0 always true, unsigned */
51214
51215 if (t == DUK__HASH_UNUSED) {
51216 break;
51217 } else if (t == DUK__HASH_DELETED) {
51218 DUK_DDD(DUK_DDDPRINT("lookup miss (deleted) i=%ld, t=%ld",
51219 (long) i, (long) t));
51220 } else {
51221 DUK_ASSERT(t < DUK_HOBJECT_GET_ESIZE(obj));
51222 if (DUK_HOBJECT_E_GET_KEY(heap, obj, t) == key) {
51223 DUK_DDD(DUK_DDDPRINT("lookup hit i=%ld, t=%ld -> key %p",
51224 (long) i, (long) t, (void *) key));
51225 *e_idx = t;
51226 *h_idx = i;
51227 return;
51228 }
51229 DUK_DDD(DUK_DDDPRINT("lookup miss i=%ld, t=%ld",
51230 (long) i, (long) t));
51231 }
51232 i = (i + step) % n;
51233
51234 /* guaranteed to finish, as hash is never full */
51235 DUK_ASSERT(i != (duk_uint32_t) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n));
51236 }
51237 }
51238#endif /* DUK_USE_HOBJECT_HASH_PART */
51239
51240 /* not found */
51241 *e_idx = -1;
51242 *h_idx = -1;
51243}
51244
51245/* For internal use: get non-accessor entry value */
51246DUK_INTERNAL duk_tval *duk_hobject_find_existing_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_hstring *key) {
51247 duk_int_t e_idx;
51248 duk_int_t h_idx;
51249
51250 DUK_ASSERT(obj != NULL);
51251 DUK_ASSERT(key != NULL);
51252 DUK_UNREF(heap);
51253
51254 duk_hobject_find_existing_entry(heap, obj, key, &e_idx, &h_idx);
51255 if (e_idx >= 0 && !DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx)) {
51256 return DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx);
51257 } else {
51258 return NULL;
51259 }
51260}
51261
51262/* For internal use: get non-accessor entry value and attributes */
51263DUK_INTERNAL duk_tval *duk_hobject_find_existing_entry_tval_ptr_and_attrs(duk_heap *heap, duk_hobject *obj, duk_hstring *key, duk_int_t *out_attrs) {
51264 duk_int_t e_idx;
51265 duk_int_t h_idx;
51266
51267 DUK_ASSERT(obj != NULL);
51268 DUK_ASSERT(key != NULL);
51269 DUK_ASSERT(out_attrs != NULL);
51270 DUK_UNREF(heap);
51271
51272 duk_hobject_find_existing_entry(heap, obj, key, &e_idx, &h_idx);
51273 if (e_idx >= 0 && !DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx)) {
51274 *out_attrs = DUK_HOBJECT_E_GET_FLAGS(heap, obj, e_idx);
51275 return DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx);
51276 } else {
51277 *out_attrs = 0;
51278 return NULL;
51279 }
51280}
51281
51282/* For internal use: get array part value */
51283DUK_INTERNAL duk_tval *duk_hobject_find_existing_array_entry_tval_ptr(duk_heap *heap, duk_hobject *obj, duk_uarridx_t i) {
51284 duk_tval *tv;
51285
51286 DUK_ASSERT(obj != NULL);
51287 DUK_UNREF(heap);
51288
51289 if (!DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
51290 return NULL;
51291 }
51292 if (i >= DUK_HOBJECT_GET_ASIZE(obj)) {
51293 return NULL;
51294 }
51295 tv = DUK_HOBJECT_A_GET_VALUE_PTR(heap, obj, i);
51296 return tv;
51297}
51298
51299/*
51300 * Allocate and initialize a new entry, resizing the properties allocation
51301 * if necessary. Returns entry index (e_idx) or throws an error if alloc fails.
51302 *
51303 * Sets the key of the entry (increasing the key's refcount), and updates
51304 * the hash part if it exists. Caller must set value and flags, and update
51305 * the entry value refcount. A decref for the previous value is not necessary.
51306 */
51307
51308DUK_LOCAL duk_bool_t duk__alloc_entry_checked(duk_hthread *thr, duk_hobject *obj, duk_hstring *key) {
51309 duk_uint32_t idx;
51310
51311 DUK_ASSERT(thr != NULL);
51312 DUK_ASSERT(obj != NULL);
51313 DUK_ASSERT(key != NULL);
51314 DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(obj) <= DUK_HOBJECT_GET_ESIZE(obj));
51315
51316#if defined(DUK_USE_ASSERTIONS)
51317 /* key must not already exist in entry part */
51318 {
51319 duk_uint_fast32_t i;
51320 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
51321 DUK_ASSERT(DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i) != key);
51322 }
51323 }
51324#endif
51325
51326 if (DUK_HOBJECT_GET_ENEXT(obj) >= DUK_HOBJECT_GET_ESIZE(obj)) {
51327 /* only need to guarantee 1 more slot, but allocation growth is in chunks */
51328 DUK_DDD(DUK_DDDPRINT("entry part full, allocate space for one more entry"));
51329 duk__grow_props_for_new_entry_item(thr, obj);
51330 }
51331 DUK_ASSERT(DUK_HOBJECT_GET_ENEXT(obj) < DUK_HOBJECT_GET_ESIZE(obj));
51332 idx = DUK_HOBJECT_POSTINC_ENEXT(obj);
51333
51334 /* previous value is assumed to be garbage, so don't touch it */
51335 DUK_HOBJECT_E_SET_KEY(thr->heap, obj, idx, key);
51336 DUK_HSTRING_INCREF(thr, key);
51337
51338#if defined(DUK_USE_HOBJECT_HASH_PART)
51339 if (DUK_UNLIKELY(DUK_HOBJECT_GET_HSIZE(obj) > 0)) {
51340 duk_uint32_t n;
51341 duk_uint32_t i, step;
51342 duk_uint32_t *h_base = DUK_HOBJECT_H_GET_BASE(thr->heap, obj);
51343
51344 n = DUK_HOBJECT_GET_HSIZE(obj);
51345 i = DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), n);
51346 step = DUK__HASH_PROBE_STEP(DUK_HSTRING_GET_HASH(key));
51347
51348 for (;;) {
51349 duk_uint32_t t = h_base[i];
51350 if (t == DUK__HASH_UNUSED || t == DUK__HASH_DELETED) {
51351 DUK_DDD(DUK_DDDPRINT("duk__alloc_entry_checked() inserted key into hash part, %ld -> %ld",
51352 (long) i, (long) idx));
51353 DUK_ASSERT_DISABLE(i >= 0); /* unsigned */
51354 DUK_ASSERT(i < DUK_HOBJECT_GET_HSIZE(obj));
51355 DUK_ASSERT_DISABLE(idx >= 0);
51356 DUK_ASSERT(idx < DUK_HOBJECT_GET_ESIZE(obj));
51357 h_base[i] = idx;
51358 break;
51359 }
51360 DUK_DDD(DUK_DDDPRINT("duk__alloc_entry_checked() miss %ld", (long) i));
51361 i = (i + step) % n;
51362
51363 /* guaranteed to find an empty slot */
51364 DUK_ASSERT(i != (duk_uint32_t) DUK__HASH_INITIAL(DUK_HSTRING_GET_HASH(key), DUK_HOBJECT_GET_HSIZE(obj)));
51365 }
51366 }
51367#endif /* DUK_USE_HOBJECT_HASH_PART */
51368
51369 /* Note: we could return the hash index here too, but it's not
51370 * needed right now.
51371 */
51372
51373 DUK_ASSERT_DISABLE(idx >= 0);
51374 DUK_ASSERT(idx < DUK_HOBJECT_GET_ESIZE(obj));
51375 DUK_ASSERT(idx < DUK_HOBJECT_GET_ENEXT(obj));
51376 return idx;
51377}
51378
51379/*
51380 * Object internal value
51381 *
51382 * Returned value is guaranteed to be reachable / incref'd, caller does not need
51383 * to incref OR decref. No proxies or accessors are invoked, no prototype walk.
51384 */
51385
51386DUK_INTERNAL duk_bool_t duk_hobject_get_internal_value(duk_heap *heap, duk_hobject *obj, duk_tval *tv_out) {
51387 duk_int_t e_idx;
51388 duk_int_t h_idx;
51389
51390 DUK_ASSERT(heap != NULL);
51391 DUK_ASSERT(obj != NULL);
51392 DUK_ASSERT(tv_out != NULL);
51393
51394 /* always in entry part, no need to look up parents etc */
51395 duk_hobject_find_existing_entry(heap, obj, DUK_HEAP_STRING_INT_VALUE(heap), &e_idx, &h_idx);
51396 if (e_idx >= 0) {
51397 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(heap, obj, e_idx));
51398 DUK_TVAL_SET_TVAL(tv_out, DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(heap, obj, e_idx));
51399 return 1;
51400 }
51401 DUK_TVAL_SET_UNDEFINED(tv_out);
51402 return 0;
51403}
51404
51405DUK_INTERNAL duk_hstring *duk_hobject_get_internal_value_string(duk_heap *heap, duk_hobject *obj) {
51406 duk_tval tv;
51407
51408 DUK_ASSERT(heap != NULL);
51409 DUK_ASSERT(obj != NULL);
51410
51411 /* This is not strictly necessary, but avoids compiler warnings; e.g.
51412 * gcc won't reliably detect that no uninitialized data is read below.
51413 */
51414 DUK_MEMZERO((void *) &tv, sizeof(duk_tval));
51415
51416 if (duk_hobject_get_internal_value(heap, obj, &tv)) {
51417 duk_hstring *h;
51418 DUK_ASSERT(DUK_TVAL_IS_STRING(&tv));
51419 h = DUK_TVAL_GET_STRING(&tv);
51420 /* No explicit check for string vs. symbol, accept both. */
51421 return h;
51422 }
51423
51424 return NULL;
51425}
51426
51427/*
51428 * Arguments handling helpers (argument map mainly).
51429 *
51430 * An arguments object has exotic behavior for some numeric indices.
51431 * Accesses may translate to identifier operations which may have
51432 * arbitrary side effects (potentially invalidating any duk_tval
51433 * pointers).
51434 */
51435
51436/* Lookup 'key' from arguments internal 'map', perform a variable lookup
51437 * if mapped, and leave the result on top of stack (and return non-zero).
51438 * Used in E5 Section 10.6 algorithms [[Get]] and [[GetOwnProperty]].
51439 */
51440DUK_LOCAL
51441duk_bool_t duk__lookup_arguments_map(duk_hthread *thr,
51442 duk_hobject *obj,
51444 duk_propdesc *temp_desc,
51445 duk_hobject **out_map,
51446 duk_hobject **out_varenv) {
51447 duk_context *ctx = (duk_context *) thr;
51448 duk_hobject *map;
51449 duk_hobject *varenv;
51450 duk_bool_t rc;
51451
51452 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
51453
51454 DUK_DDD(DUK_DDDPRINT("arguments map lookup: thr=%p, obj=%p, key=%p, temp_desc=%p "
51455 "(obj -> %!O, key -> %!O)",
51456 (void *) thr, (void *) obj, (void *) key, (void *) temp_desc,
51457 (duk_heaphdr *) obj, (duk_heaphdr *) key));
51458
51459 if (!duk_hobject_get_own_propdesc(thr, obj, DUK_HTHREAD_STRING_INT_MAP(thr), temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
51460 DUK_DDD(DUK_DDDPRINT("-> no 'map'"));
51461 return 0;
51462 }
51463
51464 map = duk_require_hobject(ctx, -1);
51465 DUK_ASSERT(map != NULL);
51466 duk_pop(ctx); /* map is reachable through obj */
51467
51468 if (!duk_hobject_get_own_propdesc(thr, map, key, temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
51469 DUK_DDD(DUK_DDDPRINT("-> 'map' exists, but key not in map"));
51470 return 0;
51471 }
51472
51473 /* [... varname] */
51474 DUK_DDD(DUK_DDDPRINT("-> 'map' exists, and contains key, key is mapped to argument/variable binding %!T",
51475 (duk_tval *) duk_get_tval(ctx, -1)));
51476 DUK_ASSERT(duk_is_string(ctx, -1)); /* guaranteed when building arguments */
51477
51478 /* get varenv for varname (callee's declarative lexical environment) */
51479 rc = duk_hobject_get_own_propdesc(thr, obj, DUK_HTHREAD_STRING_INT_VARENV(thr), temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE);
51480 DUK_UNREF(rc);
51481 DUK_ASSERT(rc != 0); /* arguments MUST have an initialized lexical environment reference */
51482 varenv = duk_require_hobject(ctx, -1);
51483 DUK_ASSERT(varenv != NULL);
51484 duk_pop(ctx); /* varenv remains reachable through 'obj' */
51485
51486 DUK_DDD(DUK_DDDPRINT("arguments varenv is: %!dO", (duk_heaphdr *) varenv));
51487
51488 /* success: leave varname in stack */
51489 *out_map = map;
51490 *out_varenv = varenv;
51491 return 1; /* [... varname] */
51492}
51493
51494/* Lookup 'key' from arguments internal 'map', and leave replacement value
51495 * on stack top if mapped (and return non-zero).
51496 * Used in E5 Section 10.6 algorithm for [[GetOwnProperty]] (used by [[Get]]).
51497 */
51498DUK_LOCAL duk_bool_t duk__check_arguments_map_for_get(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc) {
51499 duk_context *ctx = (duk_context *) thr;
51500 duk_hobject *map;
51501 duk_hobject *varenv;
51502 duk_hstring *varname;
51503
51504 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
51505
51506 if (!duk__lookup_arguments_map(thr, obj, key, temp_desc, &map, &varenv)) {
51507 DUK_DDD(DUK_DDDPRINT("arguments: key not mapped, no exotic get behavior"));
51508 return 0;
51509 }
51510
51511 /* [... varname] */
51512
51513 varname = duk_require_hstring(ctx, -1);
51514 DUK_ASSERT(varname != NULL);
51515 duk_pop(ctx); /* varname is still reachable */
51516
51517 DUK_DDD(DUK_DDDPRINT("arguments object automatic getvar for a bound variable; "
51518 "key=%!O, varname=%!O",
51519 (duk_heaphdr *) key,
51520 (duk_heaphdr *) varname));
51521
51522 (void) duk_js_getvar_envrec(thr, varenv, varname, 1 /*throw*/);
51523
51524 /* [... value this_binding] */
51525
51526 duk_pop(ctx);
51527
51528 /* leave result on stack top */
51529 return 1;
51530}
51531
51532/* Lookup 'key' from arguments internal 'map', perform a variable write if mapped.
51533 * Used in E5 Section 10.6 algorithm for [[DefineOwnProperty]] (used by [[Put]]).
51534 * Assumes stack top contains 'put' value (which is NOT popped).
51535 */
51536DUK_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) {
51537 duk_context *ctx = (duk_context *) thr;
51538 duk_hobject *map;
51539 duk_hobject *varenv;
51540 duk_hstring *varname;
51541
51542 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
51543
51544 if (!duk__lookup_arguments_map(thr, obj, key, temp_desc, &map, &varenv)) {
51545 DUK_DDD(DUK_DDDPRINT("arguments: key not mapped, no exotic put behavior"));
51546 return;
51547 }
51548
51549 /* [... put_value varname] */
51550
51551 varname = duk_require_hstring(ctx, -1);
51552 DUK_ASSERT(varname != NULL);
51553 duk_pop(ctx); /* varname is still reachable */
51554
51555 DUK_DDD(DUK_DDDPRINT("arguments object automatic putvar for a bound variable; "
51556 "key=%!O, varname=%!O, value=%!T",
51557 (duk_heaphdr *) key,
51558 (duk_heaphdr *) varname,
51559 (duk_tval *) duk_require_tval(ctx, -1)));
51560
51561 /* [... put_value] */
51562
51563 /*
51564 * Note: although arguments object variable mappings are only established
51565 * for non-strict functions (and a call to a non-strict function created
51566 * the arguments object in question), an inner strict function may be doing
51567 * the actual property write. Hence the throw_flag applied here comes from
51568 * the property write call.
51569 */
51570
51571 duk_js_putvar_envrec(thr, varenv, varname, duk_require_tval(ctx, -1), throw_flag);
51572
51573 /* [... put_value] */
51574}
51575
51576/* Lookup 'key' from arguments internal 'map', delete mapping if found.
51577 * Used in E5 Section 10.6 algorithm for [[Delete]]. Note that the
51578 * variable/argument itself (where the map points) is not deleted.
51579 */
51580DUK_LOCAL void duk__check_arguments_map_for_delete(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_propdesc *temp_desc) {
51581 duk_context *ctx = (duk_context *) thr;
51582 duk_hobject *map;
51583
51584 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
51585
51586 if (!duk_hobject_get_own_propdesc(thr, obj, DUK_HTHREAD_STRING_INT_MAP(thr), temp_desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
51587 DUK_DDD(DUK_DDDPRINT("arguments: key not mapped, no exotic delete behavior"));
51588 return;
51589 }
51590
51591 map = duk_require_hobject(ctx, -1);
51592 DUK_ASSERT(map != NULL);
51593 duk_pop(ctx); /* map is reachable through obj */
51594
51595 DUK_DDD(DUK_DDDPRINT("-> have 'map', delete key %!O from map (if exists)); ignore result",
51596 (duk_heaphdr *) key));
51597
51598 /* Note: no recursion issue, we can trust 'map' to behave */
51599 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_BEHAVIOR(map));
51600 DUK_DDD(DUK_DDDPRINT("map before deletion: %!O", (duk_heaphdr *) map));
51601 (void) duk_hobject_delprop_raw(thr, map, key, 0); /* ignore result */
51602 DUK_DDD(DUK_DDDPRINT("map after deletion: %!O", (duk_heaphdr *) map));
51603}
51604
51605/*
51606 * Ecmascript compliant [[GetOwnProperty]](P), for internal use only.
51607 *
51608 * If property is found:
51609 * - Fills descriptor fields to 'out_desc'
51610 * - If DUK_GETDESC_FLAG_PUSH_VALUE is set, pushes a value related to the
51611 * property onto the stack ('undefined' for accessor properties).
51612 * - Returns non-zero
51613 *
51614 * If property is not found:
51615 * - 'out_desc' is left in untouched state (possibly garbage)
51616 * - Nothing is pushed onto the stack (not even with DUK_GETDESC_FLAG_PUSH_VALUE
51617 * set)
51618 * - Returns zero
51619 *
51620 * Notes:
51621 *
51622 * - Getting a property descriptor may cause an allocation (and hence
51623 * GC) to take place, hence reachability and refcount of all related
51624 * values matter. Reallocation of value stack, properties, etc may
51625 * invalidate many duk_tval pointers (concretely, those which reside
51626 * in memory areas subject to reallocation). However, heap object
51627 * pointers are never affected (heap objects have stable pointers).
51628 *
51629 * - The value of a plain property is always reachable and has a non-zero
51630 * reference count.
51631 *
51632 * - The value of a virtual property is not necessarily reachable from
51633 * elsewhere and may have a refcount of zero. Hence we push it onto
51634 * the valstack for the caller, which ensures it remains reachable
51635 * while it is needed.
51636 *
51637 * - There are no virtual accessor properties. Hence, all getters and
51638 * setters are always related to concretely stored properties, which
51639 * ensures that the get/set functions in the resulting descriptor are
51640 * reachable and have non-zero refcounts. Should there be virtual
51641 * accessor properties later, this would need to change.
51642 */
51643
51644DUK_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) {
51645 duk_context *ctx = (duk_context *) thr;
51646 duk_tval *tv;
51647
51648 DUK_DDD(DUK_DDDPRINT("duk_hobject_get_own_propdesc: thr=%p, obj=%p, key=%p, out_desc=%p, flags=%lx, "
51649 "arr_idx=%ld (obj -> %!O, key -> %!O)",
51650 (void *) thr, (void *) obj, (void *) key, (void *) out_desc,
51651 (long) flags, (long) arr_idx,
51652 (duk_heaphdr *) obj, (duk_heaphdr *) key));
51653
51654 DUK_ASSERT(ctx != NULL);
51655 DUK_ASSERT(thr != NULL);
51656 DUK_ASSERT(thr->heap != NULL);
51657 DUK_ASSERT(obj != NULL);
51658 DUK_ASSERT(key != NULL);
51659 DUK_ASSERT(out_desc != NULL);
51660 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
51661
51662 /* XXX: optimize this filling behavior later */
51663 out_desc->flags = 0;
51664 out_desc->get = NULL;
51665 out_desc->set = NULL;
51666 out_desc->e_idx = -1;
51667 out_desc->h_idx = -1;
51668 out_desc->a_idx = -1;
51669
51670 /*
51671 * Array part
51672 */
51673
51674 if (DUK_HOBJECT_HAS_ARRAY_PART(obj) && arr_idx != DUK__NO_ARRAY_INDEX) {
51675 if (arr_idx < DUK_HOBJECT_GET_ASIZE(obj)) {
51676 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx);
51677 if (!DUK_TVAL_IS_UNUSED(tv)) {
51678 DUK_DDD(DUK_DDDPRINT("-> found in array part"));
51679 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
51680 duk_push_tval(ctx, tv);
51681 }
51682 /* implicit attributes */
51683 out_desc->flags = DUK_PROPDESC_FLAG_WRITABLE |
51684 DUK_PROPDESC_FLAG_CONFIGURABLE |
51685 DUK_PROPDESC_FLAG_ENUMERABLE;
51686 out_desc->a_idx = arr_idx;
51687 goto prop_found;
51688 }
51689 }
51690 /* assume array part is comprehensive (contains all array indexed elements
51691 * or none of them); hence no need to check the entries part here.
51692 */
51693 DUK_DDD(DUK_DDDPRINT("-> not found as a concrete property (has array part, "
51694 "should be there if present)"));
51695 goto prop_not_found_concrete;
51696 }
51697
51698 /*
51699 * Entries part
51700 */
51701
51702 duk_hobject_find_existing_entry(thr->heap, obj, key, &out_desc->e_idx, &out_desc->h_idx);
51703 if (out_desc->e_idx >= 0) {
51704 duk_int_t e_idx = out_desc->e_idx;
51705 out_desc->flags = DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, e_idx);
51706 if (out_desc->flags & DUK_PROPDESC_FLAG_ACCESSOR) {
51707 DUK_DDD(DUK_DDDPRINT("-> found accessor property in entry part"));
51708 out_desc->get = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, e_idx);
51709 out_desc->set = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, e_idx);
51710 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
51711 /* a dummy undefined value is pushed to make valstack
51712 * behavior uniform for caller
51713 */
51714 duk_push_undefined(ctx);
51715 }
51716 } else {
51717 DUK_DDD(DUK_DDDPRINT("-> found plain property in entry part"));
51718 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx);
51719 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
51720 duk_push_tval(ctx, tv);
51721 }
51722 }
51723 goto prop_found;
51724 }
51725
51726 /*
51727 * Not found as a concrete property, check for virtual properties.
51728 */
51729
51730 prop_not_found_concrete:
51731
51732 if (!DUK_HOBJECT_HAS_VIRTUAL_PROPERTIES(obj)) {
51733 /* Quick skip. */
51734 goto prop_not_found;
51735 }
51736
51737 if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
51738 duk_harray *a;
51739
51740 DUK_DDD(DUK_DDDPRINT("array object exotic property get for key: %!O, arr_idx: %ld",
51741 (duk_heaphdr *) key, (long) arr_idx));
51742
51743 a = (duk_harray *) obj;
51744 DUK_ASSERT_HARRAY_VALID(a);
51745
51746 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
51747 DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior"));
51748
51749 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
51750 duk_push_uint(ctx, (duk_uint_t) a->length);
51751 }
51752 out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;
51753 if (DUK_HARRAY_LENGTH_WRITABLE(a)) {
51754 out_desc->flags |= DUK_PROPDESC_FLAG_WRITABLE;
51755 }
51756
51757 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
51758 return 1; /* cannot be arguments exotic */
51759 }
51760 } else if (DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(obj)) {
51761 DUK_DDD(DUK_DDDPRINT("string object exotic property get for key: %!O, arr_idx: %ld",
51762 (duk_heaphdr *) key, (long) arr_idx));
51763
51764 if (arr_idx != DUK__NO_ARRAY_INDEX) {
51765 duk_hstring *h_val;
51766
51767 DUK_DDD(DUK_DDDPRINT("array index exists"));
51768
51769 h_val = duk_hobject_get_internal_value_string(thr->heap, obj);
51770 DUK_ASSERT(h_val);
51771 if (arr_idx < DUK_HSTRING_GET_CHARLEN(h_val)) {
51772 DUK_DDD(DUK_DDDPRINT("-> found, array index inside string"));
51773 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
51774 duk_push_hstring(ctx, h_val);
51775 duk_substring(ctx, -1, arr_idx, arr_idx + 1); /* [str] -> [substr] */
51776 }
51777 out_desc->flags = DUK_PROPDESC_FLAG_ENUMERABLE | /* E5 Section 15.5.5.2 */
51778 DUK_PROPDESC_FLAG_VIRTUAL;
51779
51780 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
51781 return 1; /* cannot be e.g. arguments exotic, since exotic 'traits' are mutually exclusive */
51782 } else {
51783 /* index is above internal string length -> property is fully normal */
51784 DUK_DDD(DUK_DDDPRINT("array index outside string -> normal property"));
51785 }
51786 } else if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
51787 duk_hstring *h_val;
51788
51789 DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior"));
51790
51791 h_val = duk_hobject_get_internal_value_string(thr->heap, obj);
51792 DUK_ASSERT(h_val != NULL);
51793 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
51794 duk_push_uint(ctx, (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h_val));
51795 }
51796 out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL; /* E5 Section 15.5.5.1 */
51797
51798 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
51799 return 1; /* cannot be arguments exotic */
51800 }
51801 }
51802#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
51803 else if (DUK_HOBJECT_IS_BUFOBJ(obj)) {
51804 duk_hbufobj *h_bufobj;
51805 duk_uint_t byte_off;
51806 duk_small_uint_t elem_size;
51807
51808 h_bufobj = (duk_hbufobj *) obj;
51809 DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
51810 DUK_DDD(DUK_DDDPRINT("bufobj property get for key: %!O, arr_idx: %ld",
51811 (duk_heaphdr *) key, (long) arr_idx));
51812
51813 if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) {
51814 DUK_DDD(DUK_DDDPRINT("array index exists"));
51815
51816 /* Careful with wrapping: arr_idx upshift may easily wrap, whereas
51817 * length downshift won't.
51818 */
51819 if (arr_idx < (h_bufobj->length >> h_bufobj->shift)) {
51820 byte_off = arr_idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
51821 elem_size = 1 << h_bufobj->shift;
51822 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
51823 duk_uint8_t *data;
51824
51825 if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
51826 data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
51827 duk_hbufobj_push_validated_read(ctx, h_bufobj, data, elem_size);
51828 } else {
51829 DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (read zero)"));
51830 duk_push_uint(ctx, 0);
51831 }
51832 }
51833 out_desc->flags = DUK_PROPDESC_FLAG_WRITABLE |
51834 DUK_PROPDESC_FLAG_VIRTUAL;
51835 if (DUK_HOBJECT_GET_CLASS_NUMBER(obj) != DUK_HOBJECT_CLASS_ARRAYBUFFER) {
51836 /* ArrayBuffer indices are non-standard and are
51837 * non-enumerable to avoid their serialization.
51838 */
51839 out_desc->flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
51840 }
51841
51842 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
51843 return 1; /* cannot be e.g. arguments exotic, since exotic 'traits' are mutually exclusive */
51844 } else {
51845 /* index is above internal buffer length -> property is fully normal */
51846 DUK_DDD(DUK_DDDPRINT("array index outside buffer -> normal property"));
51847 }
51848 } else if (key == DUK_HTHREAD_STRING_LENGTH(thr) && DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) {
51849 DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior"));
51850
51851 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
51852 /* Length in elements: take into account shift, but
51853 * intentionally don't check the underlying buffer here.
51854 */
51855 duk_push_uint(ctx, h_bufobj->length >> h_bufobj->shift);
51856 }
51857 out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL;
51858
51859 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
51860 return 1; /* cannot be arguments exotic */
51861 }
51862 }
51863#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
51864 else if (DUK_HOBJECT_HAS_EXOTIC_DUKFUNC(obj)) {
51865 DUK_DDD(DUK_DDDPRINT("duktape/c object exotic property get for key: %!O, arr_idx: %ld",
51866 (duk_heaphdr *) key, (long) arr_idx));
51867
51868 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
51869 DUK_DDD(DUK_DDDPRINT("-> found, key is 'length', length exotic behavior"));
51870
51871 if (flags & DUK_GETDESC_FLAG_PUSH_VALUE) {
51872 duk_int16_t func_nargs = ((duk_hnatfunc *) obj)->nargs;
51873 duk_push_int(ctx, func_nargs == DUK_HNATFUNC_NARGS_VARARGS ? 0 : func_nargs);
51874 }
51875 out_desc->flags = DUK_PROPDESC_FLAG_VIRTUAL; /* not enumerable */
51876
51877 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj));
51878 return 1; /* cannot be arguments exotic */
51879 }
51880 }
51881
51882 /* Array properties have exotic behavior but they are concrete,
51883 * so no special handling here.
51884 *
51885 * Arguments exotic behavior (E5 Section 10.6, [[GetOwnProperty]]
51886 * is only relevant as a post-check implemented below; hence no
51887 * check here.
51888 */
51889
51890 /*
51891 * Not found as concrete or virtual
51892 */
51893
51894 prop_not_found:
51895 DUK_DDD(DUK_DDDPRINT("-> not found (virtual, entry part, or array part)"));
51896 return 0;
51897
51898 /*
51899 * Found
51900 *
51901 * Arguments object has exotic post-processing, see E5 Section 10.6,
51902 * description of [[GetOwnProperty]] variant for arguments.
51903 */
51904
51905 prop_found:
51906 DUK_DDD(DUK_DDDPRINT("-> property found, checking for arguments exotic post-behavior"));
51907
51908 /* Notes:
51909 * - only numbered indices are relevant, so arr_idx fast reject is good
51910 * (this is valid unless there are more than 4**32-1 arguments).
51911 * - since variable lookup has no side effects, this can be skipped if
51912 * DUK_GETDESC_FLAG_PUSH_VALUE is not set.
51913 */
51914
51915 if (DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj) &&
51916 arr_idx != DUK__NO_ARRAY_INDEX &&
51917 (flags & DUK_GETDESC_FLAG_PUSH_VALUE)) {
51918 duk_propdesc temp_desc;
51919
51920 /* Magically bound variable cannot be an accessor. However,
51921 * there may be an accessor property (or a plain property) in
51922 * place with magic behavior removed. This happens e.g. when
51923 * a magic property is redefined with defineProperty().
51924 * Cannot assert for "not accessor" here.
51925 */
51926
51927 /* replaces top of stack with new value if necessary */
51928 DUK_ASSERT((flags & DUK_GETDESC_FLAG_PUSH_VALUE) != 0);
51929
51930 /* This can perform a variable lookup but only into a declarative
51931 * environment which has no side effects.
51932 */
51933 if (duk__check_arguments_map_for_get(thr, obj, key, &temp_desc)) {
51934 DUK_DDD(DUK_DDDPRINT("-> arguments exotic behavior overrides result: %!T -> %!T",
51935 (duk_tval *) duk_get_tval(ctx, -2),
51936 (duk_tval *) duk_get_tval(ctx, -1)));
51937 /* [... old_result result] -> [... result] */
51938 duk_remove_m2(ctx);
51939 }
51940 }
51941
51942 return 1;
51943}
51944
51945DUK_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) {
51946 DUK_ASSERT(thr != NULL);
51947 DUK_ASSERT(obj != NULL);
51948 DUK_ASSERT(key != NULL);
51949 DUK_ASSERT(out_desc != NULL);
51950 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
51951
51952 return duk__get_own_propdesc_raw(thr, obj, key, DUK_HSTRING_GET_ARRIDX_SLOW(key), out_desc, flags);
51953}
51954
51955/*
51956 * Ecmascript compliant [[GetProperty]](P), for internal use only.
51957 *
51958 * If property is found:
51959 * - Fills descriptor fields to 'out_desc'
51960 * - If DUK_GETDESC_FLAG_PUSH_VALUE is set, pushes a value related to the
51961 * property onto the stack ('undefined' for accessor properties).
51962 * - Returns non-zero
51963 *
51964 * If property is not found:
51965 * - 'out_desc' is left in untouched state (possibly garbage)
51966 * - Nothing is pushed onto the stack (not even with DUK_GETDESC_FLAG_PUSH_VALUE
51967 * set)
51968 * - Returns zero
51969 *
51970 * May cause arbitrary side effects and invalidate (most) duk_tval
51971 * pointers.
51972 */
51973
51974DUK_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) {
51975 duk_hobject *curr;
51976 duk_uint32_t arr_idx;
51977 duk_uint_t sanity;
51978
51979 DUK_ASSERT(thr != NULL);
51980 DUK_ASSERT(thr->heap != NULL);
51981 DUK_ASSERT(obj != NULL);
51982 DUK_ASSERT(key != NULL);
51983 DUK_ASSERT(out_desc != NULL);
51984 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
51985
51986 arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key);
51987
51988 DUK_DDD(DUK_DDDPRINT("duk__get_propdesc: thr=%p, obj=%p, key=%p, out_desc=%p, flags=%lx, "
51989 "arr_idx=%ld (obj -> %!O, key -> %!O)",
51990 (void *) thr, (void *) obj, (void *) key, (void *) out_desc,
51991 (long) flags, (long) arr_idx,
51992 (duk_heaphdr *) obj, (duk_heaphdr *) key));
51993
51994 curr = obj;
51995 DUK_ASSERT(curr != NULL);
51996 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
51997 do {
51998 if (duk__get_own_propdesc_raw(thr, curr, key, arr_idx, out_desc, flags)) {
51999 /* stack contains value (if requested), 'out_desc' is set */
52000 return 1;
52001 }
52002
52003 /* not found in 'curr', next in prototype chain; impose max depth */
52004 if (sanity-- == 0) {
52005 if (flags & DUK_GETDESC_FLAG_IGNORE_PROTOLOOP) {
52006 /* treat like property not found */
52007 break;
52008 } else {
52009 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
52010 }
52011 }
52012 curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
52013 } while (curr);
52014
52015 /* out_desc is left untouched (possibly garbage), caller must use return
52016 * value to determine whether out_desc can be looked up
52017 */
52018
52019 return 0;
52020}
52021
52022/*
52023 * Shallow fast path checks for accessing array elements with numeric
52024 * indices. The goal is to try to avoid coercing an array index to an
52025 * (interned) string for the most common lookups, in particular, for
52026 * standard Array objects.
52027 *
52028 * Interning is avoided but only for a very narrow set of cases:
52029 * - Object has array part, index is within array allocation, and
52030 * value is not unused (= key exists)
52031 * - Object has no interfering exotic behavior (e.g. arguments or
52032 * string object exotic behaviors interfere, array exotic
52033 * behavior does not).
52034 *
52035 * Current shortcoming: if key does not exist (even if it is within
52036 * the array allocation range) a slow path lookup with interning is
52037 * always required. This can probably be fixed so that there is a
52038 * quick fast path for non-existent elements as well, at least for
52039 * standard Array objects.
52040 */
52041
52042#if defined(DUK_USE_ARRAY_PROP_FASTPATH)
52043DUK_LOCAL duk_tval *duk__getprop_shallow_fastpath_array_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key) {
52044 duk_tval *tv;
52045 duk_uint32_t idx;
52046
52047 DUK_UNREF(thr);
52048
52049 if (!(DUK_HOBJECT_HAS_ARRAY_PART(obj) &&
52050 !DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj) &&
52051 !DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(obj) &&
52052 !DUK_HOBJECT_IS_BUFOBJ(obj) &&
52053 !DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
52054 /* Must have array part and no conflicting exotic behaviors.
52055 * Doesn't need to have array special behavior, e.g. Arguments
52056 * object has array part.
52057 */
52058 return NULL;
52059 }
52060
52061 /* Arrays never have other exotic behaviors. */
52062
52063 DUK_DDD(DUK_DDDPRINT("fast path attempt (no exotic string/arguments/buffer "
52064 "behavior, object has array part)"));
52065
52066#if defined(DUK_USE_FASTINT)
52067 if (DUK_TVAL_IS_FASTINT(tv_key)) {
52068 idx = duk__tval_fastint_to_arr_idx(tv_key);
52069 } else
52070#endif
52071 if (DUK_TVAL_IS_DOUBLE(tv_key)) {
52072 idx = duk__tval_number_to_arr_idx(tv_key);
52073 } else {
52074 DUK_DDD(DUK_DDDPRINT("key is not a number"));
52075 return NULL;
52076 }
52077
52078 /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which
52079 * is 0xffffffffUL. We don't need to check for that explicitly
52080 * because 0xffffffffUL will never be inside object 'a_size'.
52081 */
52082
52083 if (idx >= DUK_HOBJECT_GET_ASIZE(obj)) {
52084 DUK_DDD(DUK_DDDPRINT("key is not an array index or outside array part"));
52085 return NULL;
52086 }
52087 DUK_ASSERT(idx != 0xffffffffUL);
52088 DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
52089
52090 /* XXX: for array instances we could take a shortcut here and assume
52091 * Array.prototype doesn't contain an array index property.
52092 */
52093
52094 DUK_DDD(DUK_DDDPRINT("key is a valid array index and inside array part"));
52095 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, idx);
52096 if (!DUK_TVAL_IS_UNUSED(tv)) {
52097 DUK_DDD(DUK_DDDPRINT("-> fast path successful"));
52098 return tv;
52099 }
52100
52101 DUK_DDD(DUK_DDDPRINT("fast path attempt failed, fall back to slow path"));
52102 return NULL;
52103}
52104
52105DUK_LOCAL duk_bool_t duk__putprop_shallow_fastpath_array_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key, duk_tval *tv_val) {
52106 duk_tval *tv;
52107 duk_harray *a;
52108 duk_uint32_t idx;
52109 duk_uint32_t old_len, new_len;
52110
52111 if (!(DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj) &&
52112 DUK_HOBJECT_HAS_ARRAY_PART(obj) &&
52113 DUK_HOBJECT_HAS_EXTENSIBLE(obj))) {
52114 return 0;
52115 }
52116 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); /* caller ensures */
52117
52118 a = (duk_harray *) obj;
52119 DUK_ASSERT_HARRAY_VALID(a);
52120
52121#if defined(DUK_USE_FASTINT)
52122 if (DUK_TVAL_IS_FASTINT(tv_key)) {
52123 idx = duk__tval_fastint_to_arr_idx(tv_key);
52124 } else
52125#endif
52126 if (DUK_TVAL_IS_DOUBLE(tv_key)) {
52127 idx = duk__tval_number_to_arr_idx(tv_key);
52128 } else {
52129 DUK_DDD(DUK_DDDPRINT("key is not a number"));
52130 return 0;
52131 }
52132
52133 /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which
52134 * is 0xffffffffUL. We don't need to check for that explicitly
52135 * because 0xffffffffUL will never be inside object 'a_size'.
52136 */
52137
52138 if (idx >= DUK_HOBJECT_GET_ASIZE(obj)) { /* for resizing of array part, use slow path */
52139 return 0;
52140 }
52141 DUK_ASSERT(idx != 0xffffffffUL);
52142 DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
52143
52144 old_len = a->length;
52145
52146 if (idx >= old_len) {
52147 DUK_DDD(DUK_DDDPRINT("write new array entry requires length update "
52148 "(arr_idx=%ld, old_len=%ld)",
52149 (long) idx, (long) old_len));
52150 if (DUK_HARRAY_LENGTH_NONWRITABLE(a)) {
52151 /* The correct behavior here is either a silent error
52152 * or a TypeError, depending on strictness. Fall back
52153 * to the slow path to handle the situation.
52154 */
52155 return 0;
52156 }
52157 new_len = idx + 1;
52158
52159 ((duk_harray *) obj)->length = new_len;
52160 }
52161
52162 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, idx);
52163 DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val); /* side effects */
52164
52165 DUK_DDD(DUK_DDDPRINT("array fast path success for index %ld", (long) idx));
52166 return 1;
52167}
52168#endif /* DUK_USE_ARRAY_PROP_FASTPATH */
52169
52170/*
52171 * Fast path for bufobj getprop/putprop
52172 */
52173
52174#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
52175DUK_LOCAL duk_bool_t duk__getprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key) {
52176 duk_context *ctx;
52177 duk_uint32_t idx;
52178 duk_hbufobj *h_bufobj;
52179 duk_uint_t byte_off;
52180 duk_small_uint_t elem_size;
52181 duk_uint8_t *data;
52182
52183 ctx = (duk_context *) thr;
52184
52185 if (!DUK_HOBJECT_IS_BUFOBJ(obj)) {
52186 return 0;
52187 }
52188 h_bufobj = (duk_hbufobj *) obj;
52189 if (!DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) {
52190 return 0;
52191 }
52192
52193#if defined(DUK_USE_FASTINT)
52194 if (DUK_TVAL_IS_FASTINT(tv_key)) {
52195 idx = duk__tval_fastint_to_arr_idx(tv_key);
52196 } else
52197#endif
52198 if (DUK_TVAL_IS_DOUBLE(tv_key)) {
52199 idx = duk__tval_number_to_arr_idx(tv_key);
52200 } else {
52201 return 0;
52202 }
52203
52204 /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which
52205 * is 0xffffffffUL. We don't need to check for that explicitly
52206 * because 0xffffffffUL will never be inside bufobj length.
52207 */
52208
52209 /* Careful with wrapping (left shifting idx would be unsafe). */
52210 if (idx >= (h_bufobj->length >> h_bufobj->shift)) {
52211 return 0;
52212 }
52213 DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
52214
52215 byte_off = idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
52216 elem_size = 1 << h_bufobj->shift;
52217
52218 if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
52219 data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
52220 duk_hbufobj_push_validated_read(ctx, h_bufobj, data, elem_size);
52221 } else {
52222 DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (read zero)"));
52223 duk_push_uint(ctx, 0);
52224 }
52225
52226 return 1;
52227}
52228#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
52229
52230#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
52231DUK_LOCAL duk_bool_t duk__putprop_fastpath_bufobj_tval(duk_hthread *thr, duk_hobject *obj, duk_tval *tv_key, duk_tval *tv_val) {
52232 duk_context *ctx;
52233 duk_uint32_t idx;
52234 duk_hbufobj *h_bufobj;
52235 duk_uint_t byte_off;
52236 duk_small_uint_t elem_size;
52237 duk_uint8_t *data;
52238
52239 ctx = (duk_context *) thr;
52240
52241 if (!(DUK_HOBJECT_IS_BUFOBJ(obj) &&
52242 DUK_TVAL_IS_NUMBER(tv_val))) {
52243 return 0;
52244 }
52245 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)); /* caller ensures; rom objects are never bufobjs now */
52246
52247 h_bufobj = (duk_hbufobj *) obj;
52248 if (!DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) {
52249 return 0;
52250 }
52251
52252#if defined(DUK_USE_FASTINT)
52253 if (DUK_TVAL_IS_FASTINT(tv_key)) {
52254 idx = duk__tval_fastint_to_arr_idx(tv_key);
52255 } else
52256#endif
52257 if (DUK_TVAL_IS_DOUBLE(tv_key)) {
52258 idx = duk__tval_number_to_arr_idx(tv_key);
52259 } else {
52260 return 0;
52261 }
52262
52263 /* If index is not valid, idx will be DUK__NO_ARRAY_INDEX which
52264 * is 0xffffffffUL. We don't need to check for that explicitly
52265 * because 0xffffffffUL will never be inside bufobj length.
52266 */
52267
52268 /* Careful with wrapping (left shifting idx would be unsafe). */
52269 if (idx >= (h_bufobj->length >> h_bufobj->shift)) {
52270 return 0;
52271 }
52272 DUK_ASSERT(idx != DUK__NO_ARRAY_INDEX);
52273
52274 byte_off = idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
52275 elem_size = 1 << h_bufobj->shift;
52276
52277 /* Value is required to be a number in the fast path so there
52278 * are no side effects in write coercion.
52279 */
52280 duk_push_tval(ctx, tv_val);
52281 DUK_ASSERT(duk_is_number(ctx, -1));
52282
52283 if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
52284 data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
52285 duk_hbufobj_validated_write(ctx, h_bufobj, data, elem_size);
52286 } else {
52287 DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (write skipped)"));
52288 }
52289
52290 duk_pop(ctx);
52291 return 1;
52292}
52293#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
52294
52295/*
52296 * GETPROP: Ecmascript property read.
52297 */
52298
52299DUK_INTERNAL duk_bool_t duk_hobject_getprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) {
52300 duk_context *ctx = (duk_context *) thr;
52301 duk_tval tv_obj_copy;
52302 duk_tval tv_key_copy;
52303 duk_hobject *curr = NULL;
52304 duk_hstring *key = NULL;
52305 duk_uint32_t arr_idx = DUK__NO_ARRAY_INDEX;
52306 duk_propdesc desc;
52307 duk_uint_t sanity;
52308
52309 DUK_DDD(DUK_DDDPRINT("getprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)",
52310 (void *) thr, (void *) tv_obj, (void *) tv_key,
52311 (duk_tval *) tv_obj, (duk_tval *) tv_key));
52312
52313 DUK_ASSERT(ctx != NULL);
52314 DUK_ASSERT(thr != NULL);
52315 DUK_ASSERT(thr->heap != NULL);
52316 DUK_ASSERT(tv_obj != NULL);
52317 DUK_ASSERT(tv_key != NULL);
52318
52319 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
52320
52321 /*
52322 * Make a copy of tv_obj, tv_key, and tv_val to avoid any issues of
52323 * them being invalidated by a valstack resize.
52324 *
52325 * XXX: this is now an overkill for many fast paths. Rework this
52326 * to be faster (although switching to a valstack discipline might
52327 * be a better solution overall).
52328 */
52329
52330 DUK_TVAL_SET_TVAL(&tv_obj_copy, tv_obj);
52331 DUK_TVAL_SET_TVAL(&tv_key_copy, tv_key);
52332 tv_obj = &tv_obj_copy;
52333 tv_key = &tv_key_copy;
52334
52335 /*
52336 * Coercion and fast path processing
52337 */
52338
52339 switch (DUK_TVAL_GET_TAG(tv_obj)) {
52340 case DUK_TAG_UNDEFINED:
52341 case DUK_TAG_NULL: {
52342 /* Note: unconditional throw */
52343 DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject"));
52344#if defined(DUK_USE_PARANOID_ERRORS)
52345 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
52346#else
52347 DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot read property %s of %s",
52348 duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj));
52349#endif
52350 return 0;
52351 }
52352
52353 case DUK_TAG_BOOLEAN: {
52354 DUK_DDD(DUK_DDDPRINT("base object is a boolean, start lookup from boolean prototype"));
52355 curr = thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE];
52356 break;
52357 }
52358
52359 case DUK_TAG_STRING: {
52360 duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj);
52361 duk_int_t pop_count;
52362
52363 if (DUK_HSTRING_HAS_SYMBOL(h)) {
52364 /* Symbols (ES2015 or hidden) don't have virtual properties. */
52365 DUK_DDD(DUK_DDDPRINT("base object is a symbol, start lookup from symbol prototype"));
52366 curr = thr->builtins[DUK_BIDX_SYMBOL_PROTOTYPE];
52367 break;
52368 }
52369
52370#if defined(DUK_USE_FASTINT)
52371 if (DUK_TVAL_IS_FASTINT(tv_key)) {
52372 arr_idx = duk__tval_fastint_to_arr_idx(tv_key);
52373 DUK_DDD(DUK_DDDPRINT("base object string, key is a fast-path fastint; arr_idx %ld", (long) arr_idx));
52374 pop_count = 0;
52375 } else
52376#endif
52377 if (DUK_TVAL_IS_NUMBER(tv_key)) {
52378 arr_idx = duk__tval_number_to_arr_idx(tv_key);
52379 DUK_DDD(DUK_DDDPRINT("base object string, key is a fast-path number; arr_idx %ld", (long) arr_idx));
52380 pop_count = 0;
52381 } else {
52382 arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
52383 DUK_ASSERT(key != NULL);
52384 DUK_DDD(DUK_DDDPRINT("base object string, key is a non-fast-path number; after "
52385 "coercion key is %!T, arr_idx %ld",
52386 (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
52387 pop_count = 1;
52388 }
52389
52390 if (arr_idx != DUK__NO_ARRAY_INDEX &&
52391 arr_idx < DUK_HSTRING_GET_CHARLEN(h)) {
52392 duk_pop_n(ctx, pop_count);
52393 duk_push_hstring(ctx, h);
52394 duk_substring(ctx, -1, arr_idx, arr_idx + 1); /* [str] -> [substr] */
52395
52396 DUK_DDD(DUK_DDDPRINT("-> %!T (base is string, key is an index inside string length "
52397 "after coercion -> return char)",
52398 (duk_tval *) duk_get_tval(ctx, -1)));
52399 return 1;
52400 }
52401
52402 if (pop_count == 0) {
52403 /* This is a pretty awkward control flow, but we need to recheck the
52404 * key coercion here.
52405 */
52406 arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
52407 DUK_ASSERT(key != NULL);
52408 DUK_DDD(DUK_DDDPRINT("base object string, key is a non-fast-path number; after "
52409 "coercion key is %!T, arr_idx %ld",
52410 (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
52411 }
52412
52413 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
52414 duk_pop(ctx); /* [key] -> [] */
52415 duk_push_uint(ctx, (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h)); /* [] -> [res] */
52416
52417 DUK_DDD(DUK_DDDPRINT("-> %!T (base is string, key is 'length' after coercion -> "
52418 "return string length)",
52419 (duk_tval *) duk_get_tval(ctx, -1)));
52420 return 1;
52421 }
52422
52423 DUK_DDD(DUK_DDDPRINT("base object is a string, start lookup from string prototype"));
52424 curr = thr->builtins[DUK_BIDX_STRING_PROTOTYPE];
52425 goto lookup; /* avoid double coercion */
52426 }
52427
52428 case DUK_TAG_OBJECT: {
52429#if defined(DUK_USE_ARRAY_PROP_FASTPATH)
52430 duk_tval *tmp;
52431#endif
52432
52433 curr = DUK_TVAL_GET_OBJECT(tv_obj);
52434 DUK_ASSERT(curr != NULL);
52435
52436 /* XXX: array .length fast path (important in e.g. loops)? */
52437
52438#if defined(DUK_USE_ARRAY_PROP_FASTPATH)
52439 tmp = duk__getprop_shallow_fastpath_array_tval(thr, curr, tv_key);
52440 if (tmp) {
52441 duk_push_tval(ctx, tmp);
52442
52443 DUK_DDD(DUK_DDDPRINT("-> %!T (base is object, key is a number, array part "
52444 "fast path)",
52445 (duk_tval *) duk_get_tval(ctx, -1)));
52446 return 1;
52447 }
52448#endif
52449
52450#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
52451 if (duk__getprop_fastpath_bufobj_tval(thr, curr, tv_key) != 0) {
52452 /* Read value pushed on stack. */
52453 DUK_DDD(DUK_DDDPRINT("-> %!T (base is bufobj, key is a number, bufobj "
52454 "fast path)",
52455 (duk_tval *) duk_get_tval(ctx, -1)));
52456 return 1;
52457 }
52458#endif
52459
52460#if defined(DUK_USE_ES6_PROXY)
52461 if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(curr))) {
52462 duk_hobject *h_target;
52463
52464 if (duk__proxy_check_prop(thr, curr, DUK_STRIDX_GET, tv_key, &h_target)) {
52465 /* -> [ ... trap handler ] */
52466 DUK_DDD(DUK_DDDPRINT("-> proxy object 'get' for key %!T", (duk_tval *) tv_key));
52467 duk_push_hobject(ctx, h_target); /* target */
52468 duk_push_tval(ctx, tv_key); /* P */
52469 duk_push_tval(ctx, tv_obj); /* Receiver: Proxy object */
52470 duk_call_method(ctx, 3 /*nargs*/);
52471
52472 /* Target object must be checked for a conflicting
52473 * non-configurable property.
52474 */
52475 arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
52476 DUK_ASSERT(key != NULL);
52477
52478 if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
52479 duk_tval *tv_hook = duk_require_tval(ctx, -3); /* value from hook */
52480 duk_tval *tv_targ = duk_require_tval(ctx, -1); /* value from target */
52481 duk_bool_t datadesc_reject;
52482 duk_bool_t accdesc_reject;
52483
52484 DUK_DDD(DUK_DDDPRINT("proxy 'get': target has matching property %!O, check for "
52485 "conflicting property; tv_hook=%!T, tv_targ=%!T, desc.flags=0x%08lx, "
52486 "desc.get=%p, desc.set=%p",
52487 (duk_heaphdr *) key, (duk_tval *) tv_hook, (duk_tval *) tv_targ,
52488 (unsigned long) desc.flags,
52489 (void *) desc.get, (void *) desc.set));
52490
52491 datadesc_reject = !(desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
52492 !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) &&
52493 !(desc.flags & DUK_PROPDESC_FLAG_WRITABLE) &&
52494 !duk_js_samevalue(tv_hook, tv_targ);
52495 accdesc_reject = (desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
52496 !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) &&
52497 (desc.get == NULL) &&
52498 !DUK_TVAL_IS_UNDEFINED(tv_hook);
52499 if (datadesc_reject || accdesc_reject) {
52500 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
52501 }
52502
52503 duk_pop_2(ctx);
52504 } else {
52505 duk_pop(ctx);
52506 }
52507 return 1; /* return value */
52508 }
52509
52510 curr = h_target; /* resume lookup from target */
52511 DUK_TVAL_SET_OBJECT(tv_obj, curr);
52512 }
52513#endif /* DUK_USE_ES6_PROXY */
52514
52515 if (DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(curr)) {
52516 arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
52517 DUK_ASSERT(key != NULL);
52518
52519 if (duk__check_arguments_map_for_get(thr, curr, key, &desc)) {
52520 DUK_DDD(DUK_DDDPRINT("-> %!T (base is object with arguments exotic behavior, "
52521 "key matches magically bound property -> skip standard "
52522 "Get with replacement value)",
52523 (duk_tval *) duk_get_tval(ctx, -1)));
52524
52525 /* no need for 'caller' post-check, because 'key' must be an array index */
52526
52527 duk_remove_m2(ctx); /* [key result] -> [result] */
52528 return 1;
52529 }
52530
52531 goto lookup; /* avoid double coercion */
52532 }
52533 break;
52534 }
52535
52536 /* Buffer has virtual properties similar to string, but indexed values
52537 * are numbers, not 1-byte buffers/strings which would perform badly.
52538 */
52539 case DUK_TAG_BUFFER: {
52540 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj);
52541 duk_int_t pop_count;
52542
52543 /*
52544 * Because buffer values are often looped over, a number fast path
52545 * is important.
52546 */
52547
52548#if defined(DUK_USE_FASTINT)
52549 if (DUK_TVAL_IS_FASTINT(tv_key)) {
52550 arr_idx = duk__tval_fastint_to_arr_idx(tv_key);
52551 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path fastint; arr_idx %ld", (long) arr_idx));
52552 pop_count = 0;
52553 }
52554 else
52555#endif
52556 if (DUK_TVAL_IS_NUMBER(tv_key)) {
52557 arr_idx = duk__tval_number_to_arr_idx(tv_key);
52558 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path number; arr_idx %ld", (long) arr_idx));
52559 pop_count = 0;
52560 } else {
52561 arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
52562 DUK_ASSERT(key != NULL);
52563 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
52564 "coercion key is %!T, arr_idx %ld",
52565 (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
52566 pop_count = 1;
52567 }
52568
52569 if (arr_idx != DUK__NO_ARRAY_INDEX &&
52570 arr_idx < DUK_HBUFFER_GET_SIZE(h)) {
52571 duk_pop_n(ctx, pop_count);
52572 duk_push_uint(ctx, ((duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h))[arr_idx]);
52573
52574 DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is an index inside buffer length "
52575 "after coercion -> return byte as number)",
52576 (duk_tval *) duk_get_tval(ctx, -1)));
52577 return 1;
52578 }
52579
52580 if (pop_count == 0) {
52581 /* This is a pretty awkward control flow, but we need to recheck the
52582 * key coercion here.
52583 */
52584 arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
52585 DUK_ASSERT(key != NULL);
52586 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
52587 "coercion key is %!T, arr_idx %ld",
52588 (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
52589 }
52590
52591 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
52592 duk_pop(ctx); /* [key] -> [] */
52593 duk_push_uint(ctx, (duk_uint_t) DUK_HBUFFER_GET_SIZE(h)); /* [] -> [res] */
52594
52595 DUK_DDD(DUK_DDDPRINT("-> %!T (base is buffer, key is 'length' "
52596 "after coercion -> return buffer length)",
52597 (duk_tval *) duk_get_tval(ctx, -1)));
52598 return 1;
52599 }
52600
52601 DUK_DDD(DUK_DDDPRINT("base object is a buffer, start lookup from Uint8Array prototype"));
52602 curr = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE];
52603 goto lookup; /* avoid double coercion */
52604 }
52605
52606 case DUK_TAG_POINTER: {
52607 DUK_DDD(DUK_DDDPRINT("base object is a pointer, start lookup from pointer prototype"));
52608 curr = thr->builtins[DUK_BIDX_POINTER_PROTOTYPE];
52609 break;
52610 }
52611
52612 case DUK_TAG_LIGHTFUNC: {
52613 duk_int_t lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv_obj);
52614
52615 /* Must coerce key: if key is an object, it may coerce to e.g. 'length'. */
52616 arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
52617
52618 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
52619 duk_int_t lf_len = DUK_LFUNC_FLAGS_GET_LENGTH(lf_flags);
52620 duk_pop(ctx);
52621 duk_push_int(ctx, lf_len);
52622 return 1;
52623 } else if (key == DUK_HTHREAD_STRING_NAME(thr)) {
52624 duk_pop(ctx);
52625 duk_push_lightfunc_name(ctx, tv_obj);
52626 return 1;
52627 }
52628
52629 DUK_DDD(DUK_DDDPRINT("base object is a lightfunc, start lookup from function prototype"));
52630 curr = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
52631 goto lookup; /* avoid double coercion */
52632 }
52633
52634#if defined(DUK_USE_FASTINT)
52635 case DUK_TAG_FASTINT:
52636#endif
52637 default: {
52638 /* number */
52639 DUK_DDD(DUK_DDDPRINT("base object is a number, start lookup from number prototype"));
52640 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_obj));
52641 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_obj));
52642 curr = thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE];
52643 break;
52644 }
52645 }
52646
52647 /* key coercion (unless already coerced above) */
52648 DUK_ASSERT(key == NULL);
52649 arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
52650 DUK_ASSERT(key != NULL);
52651
52652 /*
52653 * Property lookup
52654 */
52655
52656 lookup:
52657 /* [key] (coerced) */
52658 DUK_ASSERT(curr != NULL);
52659 DUK_ASSERT(key != NULL);
52660
52661 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
52662 do {
52663 if (!duk__get_own_propdesc_raw(thr, curr, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
52664 goto next_in_chain;
52665 }
52666
52667 if (desc.get != NULL) {
52668 /* accessor with defined getter */
52669 DUK_ASSERT((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) != 0);
52670
52671 duk_pop(ctx); /* [key undefined] -> [key] */
52672 duk_push_hobject(ctx, desc.get);
52673 duk_push_tval(ctx, tv_obj); /* note: original, uncoerced base */
52674#if defined(DUK_USE_NONSTD_GETTER_KEY_ARGUMENT)
52675 duk_dup_m3(ctx);
52676 duk_call_method(ctx, 1); /* [key getter this key] -> [key retval] */
52677#else
52678 duk_call_method(ctx, 0); /* [key getter this] -> [key retval] */
52679#endif
52680 } else {
52681 /* [key value] or [key undefined] */
52682
52683 /* data property or accessor without getter */
52684 DUK_ASSERT(((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0) ||
52685 (desc.get == NULL));
52686
52687 /* if accessor without getter, return value is undefined */
52688 DUK_ASSERT(((desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) == 0) ||
52689 duk_is_undefined(ctx, -1));
52690
52691 /* Note: for an accessor without getter, falling through to
52692 * check for "caller" exotic behavior is unnecessary as
52693 * "undefined" will never activate the behavior. But it does
52694 * no harm, so we'll do it anyway.
52695 */
52696 }
52697
52698 goto found; /* [key result] */
52699
52700 next_in_chain:
52701 /* XXX: option to pretend property doesn't exist if sanity limit is
52702 * hit might be useful.
52703 */
52704 if (sanity-- == 0) {
52705 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
52706 }
52707 curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
52708 } while (curr);
52709
52710 /*
52711 * Not found
52712 */
52713
52714 duk_to_undefined(ctx, -1); /* [key] -> [undefined] (default value) */
52715
52716 DUK_DDD(DUK_DDDPRINT("-> %!T (not found)", (duk_tval *) duk_get_tval(ctx, -1)));
52717 return 0;
52718
52719 /*
52720 * Found; post-processing (Function and arguments objects)
52721 */
52722
52723 found:
52724 /* [key result] */
52725
52726#if !defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
52727 /* Special behavior for 'caller' property of (non-bound) function objects
52728 * and non-strict Arguments objects: if 'caller' -value- (!) is a strict
52729 * mode function, throw a TypeError (E5 Sections 15.3.5.4, 10.6).
52730 * Quite interestingly, a non-strict function with no formal arguments
52731 * will get an arguments object -without- special 'caller' behavior!
52732 *
52733 * The E5.1 spec is a bit ambiguous if this special behavior applies when
52734 * a bound function is the base value (not the 'caller' value): Section
52735 * 15.3.4.5 (describing bind()) states that [[Get]] for bound functions
52736 * matches that of Section 15.3.5.4 ([[Get]] for Function instances).
52737 * However, Section 13.3.5.4 has "NOTE: Function objects created using
52738 * Function.prototype.bind use the default [[Get]] internal method."
52739 * The current implementation assumes this means that bound functions
52740 * should not have the special [[Get]] behavior.
52741 *
52742 * The E5.1 spec is also a bit unclear if the TypeError throwing is
52743 * applied if the 'caller' value is a strict bound function. The
52744 * current implementation will throw even for both strict non-bound
52745 * and strict bound functions.
52746 *
52747 * See test-dev-strict-func-as-caller-prop-value.js for quite extensive
52748 * tests.
52749 *
52750 * This exotic behavior is disabled when the non-standard 'caller' property
52751 * is enabled, as it conflicts with the free use of 'caller'.
52752 */
52753 if (key == DUK_HTHREAD_STRING_CALLER(thr) &&
52754 DUK_TVAL_IS_OBJECT(tv_obj)) {
52755 duk_hobject *orig = DUK_TVAL_GET_OBJECT(tv_obj);
52756 DUK_ASSERT(orig != NULL);
52757
52758 if (DUK_HOBJECT_IS_NONBOUND_FUNCTION(orig) ||
52759 DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(orig)) {
52760 duk_hobject *h;
52761
52762 /* XXX: The TypeError is currently not applied to bound
52763 * functions because the 'strict' flag is not copied by
52764 * bind(). This may or may not be correct, the specification
52765 * only refers to the value being a "strict mode Function
52766 * object" which is ambiguous.
52767 */
52768 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(orig));
52769
52770 h = duk_get_hobject(ctx, -1); /* NULL if not an object */
52771 if (h &&
52772 DUK_HOBJECT_IS_FUNCTION(h) &&
52773 DUK_HOBJECT_HAS_STRICT(h)) {
52774 /* XXX: sufficient to check 'strict', assert for 'is function' */
52775 DUK_ERROR_TYPE(thr, DUK_STR_STRICT_CALLER_READ);
52776 }
52777 }
52778 }
52779#endif /* !DUK_USE_NONSTD_FUNC_CALLER_PROPERTY */
52780
52781 duk_remove_m2(ctx); /* [key result] -> [result] */
52782
52783 DUK_DDD(DUK_DDDPRINT("-> %!T (found)", (duk_tval *) duk_get_tval(ctx, -1)));
52784 return 1;
52785}
52786
52787/*
52788 * HASPROP: Ecmascript property existence check ("in" operator).
52789 *
52790 * Interestingly, the 'in' operator does not do any coercion of
52791 * the target object.
52792 */
52793
52794DUK_INTERNAL duk_bool_t duk_hobject_hasprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key) {
52795 duk_context *ctx = (duk_context *) thr;
52796 duk_tval tv_key_copy;
52797 duk_hobject *obj;
52799 duk_uint32_t arr_idx;
52800 duk_bool_t rc;
52801 duk_propdesc desc;
52802
52803 DUK_DDD(DUK_DDDPRINT("hasprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)",
52804 (void *) thr, (void *) tv_obj, (void *) tv_key,
52805 (duk_tval *) tv_obj, (duk_tval *) tv_key));
52806
52807 DUK_ASSERT(thr != NULL);
52808 DUK_ASSERT(thr->heap != NULL);
52809 DUK_ASSERT(tv_obj != NULL);
52810 DUK_ASSERT(tv_key != NULL);
52811 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
52812
52813 DUK_TVAL_SET_TVAL(&tv_key_copy, tv_key);
52814 tv_key = &tv_key_copy;
52815
52816 /*
52817 * The 'in' operator requires an object as its right hand side,
52818 * throwing a TypeError unconditionally if this is not the case.
52819 *
52820 * However, lightfuncs need to behave like fully fledged objects
52821 * here to be maximally transparent, so we need to handle them
52822 * here. Same goes for plain buffers which behave like ArrayBuffers.
52823 */
52824
52825 /* XXX: Refactor key coercion so that it's only called once. It can't
52826 * be trivially lifted here because the object must be type checked
52827 * first.
52828 */
52829
52830 if (DUK_TVAL_IS_OBJECT(tv_obj)) {
52831 obj = DUK_TVAL_GET_OBJECT(tv_obj);
52832 DUK_ASSERT(obj != NULL);
52833
52834 arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
52835 } else if (DUK_TVAL_IS_BUFFER(tv_obj)) {
52836 arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
52837 if (duk__key_is_plain_buf_ownprop(thr, DUK_TVAL_GET_BUFFER(tv_obj), key, arr_idx)) {
52838 rc = 1;
52839 goto pop_and_return;
52840 }
52841 obj = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE];
52842 } else if (DUK_TVAL_IS_LIGHTFUNC(tv_obj)) {
52843 arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
52844 if (duk__key_is_lightfunc_ownprop(thr, key)) {
52845 rc = 1;
52846 goto pop_and_return;
52847 }
52848
52849 /* If not found, resume existence check from Function.prototype.
52850 * We can just substitute the value in this case; nothing will
52851 * need the original base value (as would be the case with e.g.
52852 * setters/getters.
52853 */
52854 obj = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
52855 } else {
52856 /* Note: unconditional throw */
52857 DUK_DDD(DUK_DDDPRINT("base object is not an object -> reject"));
52858 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
52859 }
52860
52861 /* XXX: fast path for arrays? */
52862
52863 DUK_ASSERT(key != NULL);
52864 DUK_ASSERT(obj != NULL);
52865 DUK_UNREF(arr_idx);
52866
52867#if defined(DUK_USE_ES6_PROXY)
52868 if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
52869 duk_hobject *h_target;
52870 duk_bool_t tmp_bool;
52871
52872 /* XXX: the key in 'key in obj' is string coerced before we're called
52873 * (which is the required behavior in E5/E5.1/E6) so the key is a string
52874 * here already.
52875 */
52876
52877 if (duk__proxy_check_prop(thr, obj, DUK_STRIDX_HAS, tv_key, &h_target)) {
52878 /* [ ... key trap handler ] */
52879 DUK_DDD(DUK_DDDPRINT("-> proxy object 'has' for key %!T", (duk_tval *) tv_key));
52880 duk_push_hobject(ctx, h_target); /* target */
52881 duk_push_tval(ctx, tv_key); /* P */
52882 duk_call_method(ctx, 2 /*nargs*/);
52883 tmp_bool = duk_to_boolean(ctx, -1);
52884 if (!tmp_bool) {
52885 /* Target object must be checked for a conflicting
52886 * non-configurable property.
52887 */
52888
52889 if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */
52890 DUK_DDD(DUK_DDDPRINT("proxy 'has': target has matching property %!O, check for "
52891 "conflicting property; desc.flags=0x%08lx, "
52892 "desc.get=%p, desc.set=%p",
52893 (duk_heaphdr *) key, (unsigned long) desc.flags,
52894 (void *) desc.get, (void *) desc.set));
52895 /* XXX: Extensibility check for target uses IsExtensible(). If we
52896 * implemented the isExtensible trap and didn't reject proxies as
52897 * proxy targets, it should be respected here.
52898 */
52899 if (!((desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && /* property is configurable and */
52900 DUK_HOBJECT_HAS_EXTENSIBLE(h_target))) { /* ... target is extensible */
52901 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
52902 }
52903 }
52904 }
52905
52906 duk_pop_2(ctx); /* [ key trap_result ] -> [] */
52907 return tmp_bool;
52908 }
52909
52910 obj = h_target; /* resume check from proxy target */
52911 }
52912#endif /* DUK_USE_ES6_PROXY */
52913
52914 /* XXX: inline into a prototype walking loop? */
52915
52916 rc = duk__get_propdesc(thr, obj, key, &desc, 0 /*flags*/); /* don't push value */
52917 /* fall through */
52918
52919 pop_and_return:
52920 duk_pop(ctx); /* [ key ] -> [] */
52921 return rc;
52922}
52923
52924/*
52925 * HASPROP variant used internally.
52926 *
52927 * This primitive must never throw an error, callers rely on this.
52928 * In particular, don't throw an error for prototype loops; instead,
52929 * pretend like the property doesn't exist if a prototype sanity limit
52930 * is reached.
52931 *
52932 * Does not implement proxy behavior: if applied to a proxy object,
52933 * returns key existence on the proxy object itself.
52934 */
52935
52936DUK_INTERNAL duk_bool_t duk_hobject_hasprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key) {
52937 duk_propdesc dummy;
52938
52939 DUK_ASSERT(thr != NULL);
52940 DUK_ASSERT(thr->heap != NULL);
52941 DUK_ASSERT(obj != NULL);
52942 DUK_ASSERT(key != NULL);
52943
52944 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
52945
52946 return duk__get_propdesc(thr, obj, key, &dummy, DUK_GETDESC_FLAG_IGNORE_PROTOLOOP); /* don't push value */
52947}
52948
52949/*
52950 * Helper: handle Array object 'length' write which automatically
52951 * deletes properties, see E5 Section 15.4.5.1, step 3. This is
52952 * quite tricky to get right.
52953 *
52954 * Used by duk_hobject_putprop().
52955 */
52956
52957/* Coerce a new .length candidate to a number and check that it's a valid
52958 * .length.
52959 */
52960DUK_LOCAL duk_uint32_t duk__to_new_array_length_checked(duk_hthread *thr, duk_tval *tv) {
52961 duk_uint32_t res;
52962 duk_double_t d;
52963
52964#if !defined(DUK_USE_PREFER_SIZE)
52965#if defined(DUK_USE_FASTINT)
52966 /* When fastints are enabled, the most interesting case is assigning
52967 * a fastint to .length (e.g. arr.length = 0).
52968 */
52969 if (DUK_TVAL_IS_FASTINT(tv)) {
52970 /* Very common case. */
52971 duk_int64_t fi;
52972 fi = DUK_TVAL_GET_FASTINT(tv);
52973 if (fi < 0 || fi > 0xffffffffLL) {
52974 goto fail_range;
52975 }
52976 return (duk_uint32_t) fi;
52977 }
52978#else /* DUK_USE_FASTINT */
52979 /* When fastints are not enabled, the most interesting case is any
52980 * number.
52981 */
52982 if (DUK_TVAL_IS_DOUBLE(tv)) {
52983 d = DUK_TVAL_GET_NUMBER(tv);
52984 }
52985#endif /* DUK_USE_FASTINT */
52986 else
52987#endif /* !DUK_USE_PREFER_SIZE */
52988 {
52989 /* In all other cases, and when doing a size optimized build,
52990 * fall back to the comprehensive handler.
52991 */
52992 d = duk_js_tonumber(thr, tv);
52993 }
52994
52995 /* Refuse to update an Array's 'length' to a value outside the
52996 * 32-bit range. Negative zero is accepted as zero.
52997 */
52998 res = (duk_uint32_t) d;
52999 if ((duk_double_t) res != d) {
53000 goto fail_range;
53001 }
53002
53003 return res;
53004
53005 fail_range:
53006 DUK_ERROR_RANGE(thr, DUK_STR_INVALID_ARRAY_LENGTH);
53007 return 0; /* unreachable */
53008}
53009
53010/* Delete elements required by a smaller length, taking into account
53011 * potentially non-configurable elements. Returns non-zero if all
53012 * elements could be deleted, and zero if all or some elements could
53013 * not be deleted. Also writes final "target length" to 'out_result_len'.
53014 * This is the length value that should go into the 'length' property
53015 * (must be set by the caller). Never throws an error.
53016 */
53017DUK_LOCAL
53018duk_bool_t duk__handle_put_array_length_smaller(duk_hthread *thr,
53019 duk_hobject *obj,
53020 duk_uint32_t old_len,
53021 duk_uint32_t new_len,
53022 duk_bool_t force_flag,
53023 duk_uint32_t *out_result_len) {
53024 duk_uint32_t target_len;
53025 duk_uint_fast32_t i;
53026 duk_uint32_t arr_idx;
53028 duk_tval *tv;
53029 duk_bool_t rc;
53030
53031 DUK_DDD(DUK_DDDPRINT("new array length smaller than old (%ld -> %ld), "
53032 "probably need to remove elements",
53033 (long) old_len, (long) new_len));
53034
53035 /*
53036 * New length is smaller than old length, need to delete properties above
53037 * the new length.
53038 *
53039 * If array part exists, this is straightforward: array entries cannot
53040 * be non-configurable so this is guaranteed to work.
53041 *
53042 * If array part does not exist, array-indexed values are scattered
53043 * in the entry part, and some may not be configurable (preventing length
53044 * from becoming lower than their index + 1). To handle the algorithm
53045 * in E5 Section 15.4.5.1, step l correctly, we scan the entire property
53046 * set twice.
53047 */
53048
53049 DUK_ASSERT(thr != NULL);
53050 DUK_ASSERT(obj != NULL);
53051 DUK_ASSERT(new_len < old_len);
53052 DUK_ASSERT(out_result_len != NULL);
53053 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
53054
53055 DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj));
53056 DUK_ASSERT(DUK_HOBJECT_IS_ARRAY(obj));
53057
53058 if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
53059 /*
53060 * All defined array-indexed properties are in the array part
53061 * (we assume the array part is comprehensive), and all array
53062 * entries are writable, configurable, and enumerable. Thus,
53063 * nothing can prevent array entries from being deleted.
53064 */
53065
53066 DUK_DDD(DUK_DDDPRINT("have array part, easy case"));
53067
53068 if (old_len < DUK_HOBJECT_GET_ASIZE(obj)) {
53069 /* XXX: assertion that entries >= old_len are already unused */
53070 i = old_len;
53071 } else {
53072 i = DUK_HOBJECT_GET_ASIZE(obj);
53073 }
53074 DUK_ASSERT(i <= DUK_HOBJECT_GET_ASIZE(obj));
53075
53076 while (i > new_len) {
53077 i--;
53078 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i);
53079 DUK_TVAL_SET_UNUSED_UPDREF(thr, tv); /* side effects */
53080 }
53081
53082 *out_result_len = new_len;
53083 return 1;
53084 } else {
53085 /*
53086 * Entries part is a bit more complex
53087 */
53088
53089 /* Stage 1: find highest preventing non-configurable entry (if any).
53090 * When forcing, ignore non-configurability.
53091 */
53092
53093 DUK_DDD(DUK_DDDPRINT("no array part, slow case"));
53094
53095 DUK_DDD(DUK_DDDPRINT("array length write, no array part, stage 1: find target_len "
53096 "(highest preventing non-configurable entry (if any))"));
53097
53098 target_len = new_len;
53099 if (force_flag) {
53100 DUK_DDD(DUK_DDDPRINT("array length write, no array part; force flag -> skip stage 1"));
53101 goto skip_stage1;
53102 }
53103 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
53104 key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i);
53105 if (!key) {
53106 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: null key", (long) i));
53107 continue;
53108 }
53109 if (!DUK_HSTRING_HAS_ARRIDX(key)) {
53110 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key not an array index", (long) i));
53111 continue;
53112 }
53113
53114 DUK_ASSERT(DUK_HSTRING_HAS_ARRIDX(key)); /* XXX: macro checks for array index flag, which is unnecessary here */
53115 arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
53116 DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX);
53117 DUK_ASSERT(arr_idx < old_len); /* consistency requires this */
53118
53119 if (arr_idx < new_len) {
53120 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key is array index %ld, below new_len",
53121 (long) i, (long) arr_idx));
53122 continue;
53123 }
53124 if (DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(thr->heap, obj, i)) {
53125 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key is a relevant array index %ld, but configurable",
53126 (long) i, (long) arr_idx));
53127 continue;
53128 }
53129
53130 /* relevant array index is non-configurable, blocks write */
53131 if (arr_idx >= target_len) {
53132 DUK_DDD(DUK_DDDPRINT("entry at index %ld has arr_idx %ld, is not configurable, "
53133 "update target_len %ld -> %ld",
53134 (long) i, (long) arr_idx, (long) target_len,
53135 (long) (arr_idx + 1)));
53136 target_len = arr_idx + 1;
53137 }
53138 }
53139 skip_stage1:
53140
53141 /* stage 2: delete configurable entries above target length */
53142
53143 DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld, target_len=%ld",
53144 (long) old_len, (long) new_len, (long) target_len));
53145
53146 DUK_DDD(DUK_DDDPRINT("array length write, no array part, stage 2: remove "
53147 "entries >= target_len"));
53148
53149 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
53150 key = DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i);
53151 if (!key) {
53152 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: null key", (long) i));
53153 continue;
53154 }
53155 if (!DUK_HSTRING_HAS_ARRIDX(key)) {
53156 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key not an array index", (long) i));
53157 continue;
53158 }
53159
53160 DUK_ASSERT(DUK_HSTRING_HAS_ARRIDX(key)); /* XXX: macro checks for array index flag, which is unnecessary here */
53161 arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
53162 DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX);
53163 DUK_ASSERT(arr_idx < old_len); /* consistency requires this */
53164
53165 if (arr_idx < target_len) {
53166 DUK_DDD(DUK_DDDPRINT("skip entry index %ld: key is array index %ld, below target_len",
53167 (long) i, (long) arr_idx));
53168 continue;
53169 }
53170 DUK_ASSERT(force_flag || DUK_HOBJECT_E_SLOT_IS_CONFIGURABLE(thr->heap, obj, i)); /* stage 1 guarantees */
53171
53172 DUK_DDD(DUK_DDDPRINT("delete entry index %ld: key is array index %ld",
53173 (long) i, (long) arr_idx));
53174
53175 /*
53176 * Slow delete, but we don't care as we're already in a very slow path.
53177 * The delete always succeeds: key has no exotic behavior, property
53178 * is configurable, and no resize occurs.
53179 */
53180 rc = duk_hobject_delprop_raw(thr, obj, key, force_flag ? DUK_DELPROP_FLAG_FORCE : 0);
53181 DUK_UNREF(rc);
53182 DUK_ASSERT(rc != 0);
53183 }
53184
53185 /* stage 3: update length (done by caller), decide return code */
53186
53187 DUK_DDD(DUK_DDDPRINT("array length write, no array part, stage 3: update length (done by caller)"));
53188
53189 *out_result_len = target_len;
53190
53191 if (target_len == new_len) {
53192 DUK_DDD(DUK_DDDPRINT("target_len matches new_len, return success"));
53193 return 1;
53194 }
53195 DUK_DDD(DUK_DDDPRINT("target_len does not match new_len (some entry prevented "
53196 "full length adjustment), return error"));
53197 return 0;
53198 }
53199
53200 DUK_UNREACHABLE();
53201}
53202
53203/* XXX: is valstack top best place for argument? */
53204DUK_LOCAL duk_bool_t duk__handle_put_array_length(duk_hthread *thr, duk_hobject *obj) {
53205 duk_context *ctx = (duk_context *) thr;
53206 duk_harray *a;
53207 duk_uint32_t old_len;
53208 duk_uint32_t new_len;
53209 duk_uint32_t result_len;
53210 duk_bool_t rc;
53211
53212 DUK_DDD(DUK_DDDPRINT("handling a put operation to array 'length' exotic property, "
53213 "new val: %!T",
53214 (duk_tval *) duk_get_tval(ctx, -1)));
53215
53216 DUK_ASSERT(thr != NULL);
53217 DUK_ASSERT(ctx != NULL);
53218 DUK_ASSERT(obj != NULL);
53219
53220 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
53221
53222 DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj));
53223 DUK_ASSERT(DUK_HOBJECT_IS_ARRAY(obj));
53224 a = (duk_harray *) obj;
53225 DUK_ASSERT_HARRAY_VALID(a);
53226
53227 DUK_ASSERT(duk_is_valid_index(ctx, -1));
53228
53229 /*
53230 * Get old and new length
53231 */
53232
53233 old_len = a->length;
53234 new_len = duk__to_new_array_length_checked(thr, DUK_GET_TVAL_NEGIDX(ctx, -1));
53235 DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld", (long) old_len, (long) new_len));
53236
53237 /*
53238 * Writability check
53239 */
53240
53241 if (DUK_HARRAY_LENGTH_NONWRITABLE(a)) {
53242 DUK_DDD(DUK_DDDPRINT("length is not writable, fail"));
53243 return 0;
53244 }
53245
53246 /*
53247 * New length not lower than old length => no changes needed
53248 * (not even array allocation).
53249 */
53250
53251 if (new_len >= old_len) {
53252 DUK_DDD(DUK_DDDPRINT("new length is same or higher than old length, just update length, no deletions"));
53253 a->length = new_len;
53254 return 1;
53255 }
53256
53257 DUK_DDD(DUK_DDDPRINT("new length is lower than old length, probably must delete entries"));
53258
53259 /*
53260 * New length lower than old length => delete elements, then
53261 * update length.
53262 *
53263 * Note: even though a bunch of elements have been deleted, the 'desc' is
53264 * still valid as properties haven't been resized (and entries compacted).
53265 */
53266
53267 rc = duk__handle_put_array_length_smaller(thr, obj, old_len, new_len, 0 /*force_flag*/, &result_len);
53268 DUK_ASSERT(result_len >= new_len && result_len <= old_len);
53269
53270 a->length = result_len;
53271
53272 /* XXX: shrink array allocation or entries compaction here? */
53273
53274 return rc;
53275}
53276
53277/*
53278 * PUTPROP: Ecmascript property write.
53279 *
53280 * Unlike Ecmascript primitive which returns nothing, returns 1 to indicate
53281 * success and 0 to indicate failure (assuming throw is not set).
53282 *
53283 * This is an extremely tricky function. Some examples:
53284 *
53285 * * Currently a decref may trigger a GC, which may compact an object's
53286 * property allocation. Consequently, any entry indices (e_idx) will
53287 * be potentially invalidated by a decref.
53288 *
53289 * * Exotic behaviors (strings, arrays, arguments object) require,
53290 * among other things:
53291 *
53292 * - Preprocessing before and postprocessing after an actual property
53293 * write. For example, array index write requires pre-checking the
53294 * array 'length' property for access control, and may require an
53295 * array 'length' update after the actual write has succeeded (but
53296 * not if it fails).
53297 *
53298 * - Deletion of multiple entries, as a result of array 'length' write.
53299 *
53300 * * Input values are taken as pointers which may point to the valstack.
53301 * If valstack is resized because of the put (this may happen at least
53302 * when the array part is abandoned), the pointers can be invalidated.
53303 * (We currently make a copy of all of the input values to avoid issues.)
53304 */
53305
53306DUK_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) {
53307 duk_context *ctx = (duk_context *) thr;
53308 duk_tval tv_obj_copy;
53309 duk_tval tv_key_copy;
53310 duk_tval tv_val_copy;
53311 duk_hobject *orig = NULL; /* NULL if tv_obj is primitive */
53312 duk_hobject *curr;
53313 duk_hstring *key = NULL;
53314 duk_propdesc desc;
53315 duk_tval *tv;
53316 duk_uint32_t arr_idx;
53317 duk_bool_t rc;
53318 duk_int_t e_idx;
53319 duk_uint_t sanity;
53320 duk_uint32_t new_array_length = 0; /* 0 = no update */
53321
53322 DUK_DDD(DUK_DDDPRINT("putprop: thr=%p, obj=%p, key=%p, val=%p, throw=%ld "
53323 "(obj -> %!T, key -> %!T, val -> %!T)",
53324 (void *) thr, (void *) tv_obj, (void *) tv_key, (void *) tv_val,
53325 (long) throw_flag, (duk_tval *) tv_obj, (duk_tval *) tv_key, (duk_tval *) tv_val));
53326
53327 DUK_ASSERT(thr != NULL);
53328 DUK_ASSERT(thr->heap != NULL);
53329 DUK_ASSERT(ctx != NULL);
53330 DUK_ASSERT(tv_obj != NULL);
53331 DUK_ASSERT(tv_key != NULL);
53332 DUK_ASSERT(tv_val != NULL);
53333
53334 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
53335
53336 /*
53337 * Make a copy of tv_obj, tv_key, and tv_val to avoid any issues of
53338 * them being invalidated by a valstack resize.
53339 *
53340 * XXX: this is an overkill for some paths, so optimize this later
53341 * (or maybe switch to a stack arguments model entirely).
53342 */
53343
53344 DUK_TVAL_SET_TVAL(&tv_obj_copy, tv_obj);
53345 DUK_TVAL_SET_TVAL(&tv_key_copy, tv_key);
53346 DUK_TVAL_SET_TVAL(&tv_val_copy, tv_val);
53347 tv_obj = &tv_obj_copy;
53348 tv_key = &tv_key_copy;
53349 tv_val = &tv_val_copy;
53350
53351 /*
53352 * Coercion and fast path processing.
53353 */
53354
53355 switch (DUK_TVAL_GET_TAG(tv_obj)) {
53356 case DUK_TAG_UNDEFINED:
53357 case DUK_TAG_NULL: {
53358 /* Note: unconditional throw */
53359 DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject (object=%!iT)",
53360 (duk_tval *) tv_obj));
53361#if defined(DUK_USE_PARANOID_ERRORS)
53362 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
53363#else
53364 DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot write property %s of %s",
53365 duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj));
53366#endif
53367 return 0;
53368 }
53369
53370 case DUK_TAG_BOOLEAN: {
53371 DUK_DDD(DUK_DDDPRINT("base object is a boolean, start lookup from boolean prototype"));
53372 curr = thr->builtins[DUK_BIDX_BOOLEAN_PROTOTYPE];
53373 break;
53374 }
53375
53376 case DUK_TAG_STRING: {
53377 duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj);
53378
53379 /*
53380 * Note: currently no fast path for array index writes.
53381 * They won't be possible anyway as strings are immutable.
53382 */
53383
53384 DUK_ASSERT(key == NULL);
53385 arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
53386 DUK_ASSERT(key != NULL);
53387
53388 if (DUK_HSTRING_HAS_SYMBOL(h)) {
53389 /* Symbols (ES2015 or hidden) don't have virtual properties. */
53390 curr = thr->builtins[DUK_BIDX_SYMBOL_PROTOTYPE];
53391 goto lookup;
53392 }
53393
53394 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
53395 goto fail_not_writable;
53396 }
53397
53398 if (arr_idx != DUK__NO_ARRAY_INDEX &&
53399 arr_idx < DUK_HSTRING_GET_CHARLEN(h)) {
53400 goto fail_not_writable;
53401 }
53402
53403 DUK_DDD(DUK_DDDPRINT("base object is a string, start lookup from string prototype"));
53404 curr = thr->builtins[DUK_BIDX_STRING_PROTOTYPE];
53405 goto lookup; /* avoid double coercion */
53406 }
53407
53408 case DUK_TAG_OBJECT: {
53409 orig = DUK_TVAL_GET_OBJECT(tv_obj);
53410 DUK_ASSERT(orig != NULL);
53411
53412#if defined(DUK_USE_ROM_OBJECTS)
53413 /* With this check in place fast paths won't need read-only
53414 * object checks. This is technically incorrect if there are
53415 * setters that cause no writes to ROM objects, but current
53416 * built-ins don't have such setters.
53417 */
53418 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) orig)) {
53419 DUK_DD(DUK_DDPRINT("attempt to putprop on read-only target object"));
53420 goto fail_not_writable_no_pop; /* Must avoid duk_pop() in exit path */
53421 }
53422#endif
53423
53424 /* The fast path for array property put is not fully compliant:
53425 * If one places conflicting number-indexed properties into
53426 * Array.prototype (for example, a non-writable Array.prototype[7])
53427 * the fast path will incorrectly ignore them.
53428 *
53429 * This fast path could be made compliant by falling through
53430 * to the slow path if the previous value was UNUSED. This would
53431 * also remove the need to check for extensibility. Right now a
53432 * non-extensible array is slower than an extensible one as far
53433 * as writes are concerned.
53434 *
53435 * The fast path behavior is documented in more detail here:
53436 * tests/ecmascript/test-misc-array-fast-write.js
53437 */
53438
53439 /* XXX: array .length? */
53440
53441#if defined(DUK_USE_ARRAY_PROP_FASTPATH)
53442 if (duk__putprop_shallow_fastpath_array_tval(thr, orig, tv_key, tv_val) != 0) {
53443 DUK_DDD(DUK_DDDPRINT("array fast path success"));
53444 return 1;
53445 }
53446#endif
53447
53448#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
53449 if (duk__putprop_fastpath_bufobj_tval(thr, orig, tv_key, tv_val) != 0) {
53450 DUK_DDD(DUK_DDDPRINT("base is bufobj, key is a number, bufobj fast path"));
53451 return 1;
53452 }
53453#endif
53454
53455#if defined(DUK_USE_ES6_PROXY)
53456 if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(orig))) {
53457 duk_hobject *h_target;
53458 duk_bool_t tmp_bool;
53459
53460 if (duk__proxy_check_prop(thr, orig, DUK_STRIDX_SET, tv_key, &h_target)) {
53461 /* -> [ ... trap handler ] */
53462 DUK_DDD(DUK_DDDPRINT("-> proxy object 'set' for key %!T", (duk_tval *) tv_key));
53463 duk_push_hobject(ctx, h_target); /* target */
53464 duk_push_tval(ctx, tv_key); /* P */
53465 duk_push_tval(ctx, tv_val); /* V */
53466 duk_push_tval(ctx, tv_obj); /* Receiver: Proxy object */
53467 duk_call_method(ctx, 4 /*nargs*/);
53468 tmp_bool = duk_to_boolean(ctx, -1);
53469 duk_pop(ctx);
53470 if (!tmp_bool) {
53471 goto fail_proxy_rejected;
53472 }
53473
53474 /* Target object must be checked for a conflicting
53475 * non-configurable property.
53476 */
53477 arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
53478 DUK_ASSERT(key != NULL);
53479
53480 if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, DUK_GETDESC_FLAG_PUSH_VALUE)) {
53481 duk_tval *tv_targ = duk_require_tval(ctx, -1);
53482 duk_bool_t datadesc_reject;
53483 duk_bool_t accdesc_reject;
53484
53485 DUK_DDD(DUK_DDDPRINT("proxy 'set': target has matching property %!O, check for "
53486 "conflicting property; tv_val=%!T, tv_targ=%!T, desc.flags=0x%08lx, "
53487 "desc.get=%p, desc.set=%p",
53488 (duk_heaphdr *) key, (duk_tval *) tv_val, (duk_tval *) tv_targ,
53489 (unsigned long) desc.flags,
53490 (void *) desc.get, (void *) desc.set));
53491
53492 datadesc_reject = !(desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
53493 !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) &&
53494 !(desc.flags & DUK_PROPDESC_FLAG_WRITABLE) &&
53495 !duk_js_samevalue(tv_val, tv_targ);
53496 accdesc_reject = (desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
53497 !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) &&
53498 (desc.set == NULL);
53499 if (datadesc_reject || accdesc_reject) {
53500 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
53501 }
53502
53503 duk_pop_2(ctx);
53504 } else {
53505 duk_pop(ctx);
53506 }
53507 return 1; /* success */
53508 }
53509
53510 orig = h_target; /* resume write to target */
53511 DUK_TVAL_SET_OBJECT(tv_obj, orig);
53512 }
53513#endif /* DUK_USE_ES6_PROXY */
53514
53515 curr = orig;
53516 break;
53517 }
53518
53519 case DUK_TAG_BUFFER: {
53520 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj);
53521 duk_int_t pop_count = 0;
53522
53523 /*
53524 * Because buffer values may be looped over and read/written
53525 * from, an array index fast path is important.
53526 */
53527
53528#if defined(DUK_USE_FASTINT)
53529 if (DUK_TVAL_IS_FASTINT(tv_key)) {
53530 arr_idx = duk__tval_fastint_to_arr_idx(tv_key);
53531 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path fastint; arr_idx %ld", (long) arr_idx));
53532 pop_count = 0;
53533 } else
53534#endif
53535 if (DUK_TVAL_IS_NUMBER(tv_key)) {
53536 arr_idx = duk__tval_number_to_arr_idx(tv_key);
53537 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a fast-path number; arr_idx %ld", (long) arr_idx));
53538 pop_count = 0;
53539 } else {
53540 arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
53541 DUK_ASSERT(key != NULL);
53542 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
53543 "coercion key is %!T, arr_idx %ld",
53544 (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
53545 pop_count = 1;
53546 }
53547
53548 if (arr_idx != DUK__NO_ARRAY_INDEX &&
53549 arr_idx < DUK_HBUFFER_GET_SIZE(h)) {
53550 duk_uint8_t *data;
53551 DUK_DDD(DUK_DDDPRINT("writing to buffer data at index %ld", (long) arr_idx));
53552 data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h);
53553
53554 /* XXX: duk_to_int() ensures we'll get 8 lowest bits as
53555 * as input is within duk_int_t range (capped outside it).
53556 */
53557#if defined(DUK_USE_FASTINT)
53558 /* Buffer writes are often integers. */
53559 if (DUK_TVAL_IS_FASTINT(tv_val)) {
53560 data[arr_idx] = (duk_uint8_t) DUK_TVAL_GET_FASTINT_U32(tv_val);
53561 }
53562 else
53563#endif
53564 {
53565 duk_push_tval(ctx, tv_val);
53566 data[arr_idx] = (duk_uint8_t) duk_to_uint32(ctx, -1);
53567 pop_count++;
53568 }
53569
53570 duk_pop_n(ctx, pop_count);
53571 DUK_DDD(DUK_DDDPRINT("result: success (buffer data write)"));
53572 return 1;
53573 }
53574
53575 if (pop_count == 0) {
53576 /* This is a pretty awkward control flow, but we need to recheck the
53577 * key coercion here.
53578 */
53579 arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
53580 DUK_ASSERT(key != NULL);
53581 DUK_DDD(DUK_DDDPRINT("base object buffer, key is a non-fast-path number; after "
53582 "coercion key is %!T, arr_idx %ld",
53583 (duk_tval *) duk_get_tval(ctx, -1), (long) arr_idx));
53584 }
53585
53586 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
53587 goto fail_not_writable;
53588 }
53589
53590 DUK_DDD(DUK_DDDPRINT("base object is a buffer, start lookup from Uint8Array prototype"));
53591 curr = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE];
53592 goto lookup; /* avoid double coercion */
53593 }
53594
53595 case DUK_TAG_POINTER: {
53596 DUK_DDD(DUK_DDDPRINT("base object is a pointer, start lookup from pointer prototype"));
53597 curr = thr->builtins[DUK_BIDX_POINTER_PROTOTYPE];
53598 break;
53599 }
53600
53601 case DUK_TAG_LIGHTFUNC: {
53602 /* All lightfunc own properties are non-writable and the lightfunc
53603 * is considered non-extensible. However, the write may be captured
53604 * by an inherited setter which means we can't stop the lookup here.
53605 */
53606
53607 arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
53608
53609 if (duk__key_is_lightfunc_ownprop(thr, key)) {
53610 goto fail_not_writable;
53611 }
53612
53613 DUK_DDD(DUK_DDDPRINT("base object is a lightfunc, start lookup from function prototype"));
53614 curr = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
53615 goto lookup; /* avoid double coercion */
53616 }
53617
53618#if defined(DUK_USE_FASTINT)
53619 case DUK_TAG_FASTINT:
53620#endif
53621 default: {
53622 /* number */
53623 DUK_DDD(DUK_DDDPRINT("base object is a number, start lookup from number prototype"));
53624 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_obj));
53625 curr = thr->builtins[DUK_BIDX_NUMBER_PROTOTYPE];
53626 break;
53627 }
53628 }
53629
53630 DUK_ASSERT(key == NULL);
53631 arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
53632 DUK_ASSERT(key != NULL);
53633
53634 lookup:
53635
53636 /*
53637 * Check whether the property already exists in the prototype chain.
53638 * Note that the actual write goes into the original base object
53639 * (except if an accessor property captures the write).
53640 */
53641
53642 /* [key] */
53643
53644 DUK_ASSERT(curr != NULL);
53645 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
53646 do {
53647 if (!duk__get_own_propdesc_raw(thr, curr, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */
53648 goto next_in_chain;
53649 }
53650
53651 if (desc.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
53652 /*
53653 * Found existing accessor property (own or inherited).
53654 * Call setter with 'this' set to orig, and value as the only argument.
53655 * Setter calls are OK even for ROM objects.
53656 *
53657 * Note: no exotic arguments object behavior, because [[Put]] never
53658 * calls [[DefineOwnProperty]] (E5 Section 8.12.5, step 5.b).
53659 */
53660
53661 duk_hobject *setter;
53662
53663 DUK_DD(DUK_DDPRINT("put to an own or inherited accessor, calling setter"));
53664
53665 setter = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, curr, desc.e_idx);
53666 if (!setter) {
53667 goto fail_no_setter;
53668 }
53669 duk_push_hobject(ctx, setter);
53670 duk_push_tval(ctx, tv_obj); /* note: original, uncoerced base */
53671 duk_push_tval(ctx, tv_val); /* [key setter this val] */
53672#if defined(DUK_USE_NONSTD_SETTER_KEY_ARGUMENT)
53673 duk_dup_m4(ctx);
53674 duk_call_method(ctx, 2); /* [key setter this val key] -> [key retval] */
53675#else
53676 duk_call_method(ctx, 1); /* [key setter this val] -> [key retval] */
53677#endif
53678 duk_pop(ctx); /* ignore retval -> [key] */
53679 goto success_no_arguments_exotic;
53680 }
53681
53682 if (orig == NULL) {
53683 /*
53684 * Found existing own or inherited plain property, but original
53685 * base is a primitive value.
53686 */
53687 DUK_DD(DUK_DDPRINT("attempt to create a new property in a primitive base object"));
53688 goto fail_base_primitive;
53689 }
53690
53691 if (curr != orig) {
53692 /*
53693 * Found existing inherited plain property.
53694 * Do an access control check, and if OK, write
53695 * new property to 'orig'.
53696 */
53697 if (!DUK_HOBJECT_HAS_EXTENSIBLE(orig)) {
53698 DUK_DD(DUK_DDPRINT("found existing inherited plain property, but original object is not extensible"));
53699 goto fail_not_extensible;
53700 }
53701 if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
53702 DUK_DD(DUK_DDPRINT("found existing inherited plain property, original object is extensible, but inherited property is not writable"));
53703 goto fail_not_writable;
53704 }
53705 DUK_DD(DUK_DDPRINT("put to new property, object extensible, inherited property found and is writable"));
53706 goto create_new;
53707 } else {
53708 /*
53709 * Found existing own (non-inherited) plain property.
53710 * Do an access control check and update in place.
53711 */
53712
53713 if (!(desc.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
53714 DUK_DD(DUK_DDPRINT("found existing own (non-inherited) plain property, but property is not writable"));
53715 goto fail_not_writable;
53716 }
53717 if (desc.flags & DUK_PROPDESC_FLAG_VIRTUAL) {
53718 DUK_DD(DUK_DDPRINT("found existing own (non-inherited) virtual property, property is writable"));
53719
53720 if (DUK_HOBJECT_IS_ARRAY(curr)) {
53721 /*
53722 * Write to 'length' of an array is a very complex case
53723 * handled in a helper which updates both the array elements
53724 * and writes the new 'length'. The write may result in an
53725 * unconditional RangeError or a partial write (indicated
53726 * by a return code).
53727 *
53728 * Note: the helper has an unnecessary writability check
53729 * for 'length', we already know it is writable.
53730 */
53731 DUK_ASSERT(key == DUK_HTHREAD_STRING_LENGTH(thr)); /* only virtual array property */
53732
53733 DUK_DDD(DUK_DDDPRINT("writing existing 'length' property to array exotic, invoke complex helper"));
53734
53735 /* XXX: the helper currently assumes stack top contains new
53736 * 'length' value and the whole calling convention is not very
53737 * compatible with what we need.
53738 */
53739
53740 duk_push_tval(ctx, tv_val); /* [key val] */
53741 rc = duk__handle_put_array_length(thr, orig);
53742 duk_pop(ctx); /* [key val] -> [key] */
53743 if (!rc) {
53744 goto fail_array_length_partial;
53745 }
53746
53747 /* key is 'length', cannot match argument exotic behavior */
53748 goto success_no_arguments_exotic;
53749 }
53750#if defined(DUK_USE_BUFFEROBJECT_SUPPORT)
53751 else if (DUK_HOBJECT_IS_BUFOBJ(curr)) {
53752 duk_hbufobj *h_bufobj;
53753 duk_uint_t byte_off;
53754 duk_small_uint_t elem_size;
53755
53756 h_bufobj = (duk_hbufobj *) curr;
53757 DUK_ASSERT_HBUFOBJ_VALID(h_bufobj);
53758
53759 DUK_DD(DUK_DDPRINT("writable virtual property is in buffer object"));
53760
53761 /* Careful with wrapping: arr_idx upshift may easily wrap, whereas
53762 * length downshift won't.
53763 */
53764 if (arr_idx < (h_bufobj->length >> h_bufobj->shift) && DUK_HBUFOBJ_HAS_VIRTUAL_INDICES(h_bufobj)) {
53765 duk_uint8_t *data;
53766 DUK_DDD(DUK_DDDPRINT("writing to buffer data at index %ld", (long) arr_idx));
53767
53768 DUK_ASSERT(arr_idx != DUK__NO_ARRAY_INDEX); /* index/length check guarantees */
53769 byte_off = arr_idx << h_bufobj->shift; /* no wrap assuming h_bufobj->length is valid */
53770 elem_size = 1 << h_bufobj->shift;
53771
53772 /* Coerce to number before validating pointers etc so that the
53773 * number coercions in duk_hbufobj_validated_write() are
53774 * guaranteed to be side effect free and not invalidate the
53775 * pointer checks we do here.
53776 */
53777 duk_push_tval(ctx, tv_val);
53778 (void) duk_to_number_m1(ctx);
53779
53780 if (h_bufobj->buf != NULL && DUK_HBUFOBJ_VALID_BYTEOFFSET_EXCL(h_bufobj, byte_off + elem_size)) {
53781 data = (duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(thr->heap, h_bufobj->buf) + h_bufobj->offset + byte_off;
53782 duk_hbufobj_validated_write(ctx, h_bufobj, data, elem_size);
53783 } else {
53784 DUK_D(DUK_DPRINT("bufobj access out of underlying buffer, ignoring (write skipped)"));
53785 }
53786 duk_pop(ctx);
53787 goto success_no_arguments_exotic;
53788 }
53789 }
53790#endif /* DUK_USE_BUFFEROBJECT_SUPPORT */
53791
53792 DUK_D(DUK_DPRINT("should not happen, key %!O", key));
53793 goto fail_internal; /* should not happen */
53794 }
53795 DUK_DD(DUK_DDPRINT("put to existing own plain property, property is writable"));
53796 goto update_old;
53797 }
53798 DUK_UNREACHABLE();
53799
53800 next_in_chain:
53801 /* XXX: option to pretend property doesn't exist if sanity limit is
53802 * hit might be useful.
53803 */
53804 if (sanity-- == 0) {
53805 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
53806 }
53807 curr = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, curr);
53808 } while (curr);
53809
53810 /*
53811 * Property not found in prototype chain.
53812 */
53813
53814 DUK_DDD(DUK_DDDPRINT("property not found in prototype chain"));
53815
53816 if (orig == NULL) {
53817 DUK_DD(DUK_DDPRINT("attempt to create a new property in a primitive base object"));
53818 goto fail_base_primitive;
53819 }
53820
53821 if (!DUK_HOBJECT_HAS_EXTENSIBLE(orig)) {
53822 DUK_DD(DUK_DDPRINT("put to a new property (not found in prototype chain), but original object not extensible"));
53823 goto fail_not_extensible;
53824 }
53825
53826 goto create_new;
53827
53828 update_old:
53829
53830 /*
53831 * Update an existing property of the base object.
53832 */
53833
53834 /* [key] */
53835
53836 DUK_DDD(DUK_DDDPRINT("update an existing property of the original object"));
53837
53838 DUK_ASSERT(orig != NULL);
53839#if defined(DUK_USE_ROM_OBJECTS)
53840 /* This should not happen because DUK_TAG_OBJECT case checks
53841 * for this already, but check just in case.
53842 */
53843 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) orig)) {
53844 goto fail_not_writable;
53845 }
53846#endif
53847
53848 /* Although there are writable virtual properties (e.g. plain buffer
53849 * and buffer object number indices), they are handled before we come
53850 * here.
53851 */
53852 DUK_ASSERT((desc.flags & DUK_PROPDESC_FLAG_VIRTUAL) == 0);
53853 DUK_ASSERT(desc.a_idx >= 0 || desc.e_idx >= 0);
53854
53855 /* Array own property .length is handled above. */
53856 DUK_ASSERT(!(DUK_HOBJECT_IS_ARRAY(orig) && key == DUK_HTHREAD_STRING_LENGTH(thr)));
53857
53858 if (desc.e_idx >= 0) {
53859 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, orig, desc.e_idx);
53860 DUK_DDD(DUK_DDDPRINT("previous entry value: %!iT", (duk_tval *) tv));
53861 DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val); /* side effects; e_idx may be invalidated */
53862 /* don't touch property attributes or hash part */
53863 DUK_DD(DUK_DDPRINT("put to an existing entry at index %ld -> new value %!iT",
53864 (long) desc.e_idx, (duk_tval *) tv));
53865 } else {
53866 /* Note: array entries are always writable, so the writability check
53867 * above is pointless for them. The check could be avoided with some
53868 * refactoring but is probably not worth it.
53869 */
53870
53871 DUK_ASSERT(desc.a_idx >= 0);
53872 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, orig, desc.a_idx);
53873 DUK_DDD(DUK_DDDPRINT("previous array value: %!iT", (duk_tval *) tv));
53874 DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv_val); /* side effects; a_idx may be invalidated */
53875 DUK_DD(DUK_DDPRINT("put to an existing array entry at index %ld -> new value %!iT",
53876 (long) desc.a_idx, (duk_tval *) tv));
53877 }
53878
53879 /* Regardless of whether property is found in entry or array part,
53880 * it may have arguments exotic behavior (array indices may reside
53881 * in entry part for abandoned / non-existent array parts).
53882 */
53883 goto success_with_arguments_exotic;
53884
53885 create_new:
53886
53887 /*
53888 * Create a new property in the original object.
53889 *
53890 * Exotic properties need to be reconsidered here from a write
53891 * perspective (not just property attributes perspective).
53892 * However, the property does not exist in the object already,
53893 * so this limits the kind of exotic properties that apply.
53894 */
53895
53896 /* [key] */
53897
53898 DUK_DDD(DUK_DDDPRINT("create new property to original object"));
53899
53900 DUK_ASSERT(orig != NULL);
53901
53902 /* Array own property .length is handled above. */
53903 DUK_ASSERT(!(DUK_HOBJECT_IS_ARRAY(orig) && key == DUK_HTHREAD_STRING_LENGTH(thr)));
53904
53905#if defined(DUK_USE_ROM_OBJECTS)
53906 /* This should not happen because DUK_TAG_OBJECT case checks
53907 * for this already, but check just in case.
53908 */
53909 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) orig)) {
53910 goto fail_not_writable;
53911 }
53912#endif
53913
53914 /* Not possible because array object 'length' is present
53915 * from its creation and cannot be deleted, and is thus
53916 * caught as an existing property above.
53917 */
53918 DUK_ASSERT(!(DUK_HOBJECT_HAS_EXOTIC_ARRAY(orig) &&
53919 key == DUK_HTHREAD_STRING_LENGTH(thr)));
53920
53921 if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(orig) &&
53922 arr_idx != DUK__NO_ARRAY_INDEX) {
53923 /* automatic length update */
53924 duk_uint32_t old_len;
53925 duk_harray *a;
53926
53927 a = (duk_harray *) orig;
53928 DUK_ASSERT_HARRAY_VALID(a);
53929
53930 old_len = a->length;
53931
53932 if (arr_idx >= old_len) {
53933 DUK_DDD(DUK_DDDPRINT("write new array entry requires length update "
53934 "(arr_idx=%ld, old_len=%ld)",
53935 (long) arr_idx, (long) old_len));
53936
53937 if (DUK_HARRAY_LENGTH_NONWRITABLE(a)) {
53938 DUK_DD(DUK_DDPRINT("attempt to extend array, but array 'length' is not writable"));
53939 goto fail_not_writable;
53940 }
53941
53942 /* Note: actual update happens once write has been completed
53943 * without error below. The write should always succeed
53944 * from a specification viewpoint, but we may e.g. run out
53945 * of memory. It's safer in this order.
53946 */
53947
53948 DUK_ASSERT(arr_idx != 0xffffffffUL);
53949 new_array_length = arr_idx + 1; /* flag for later write */
53950 } else {
53951 DUK_DDD(DUK_DDDPRINT("write new array entry does not require length update "
53952 "(arr_idx=%ld, old_len=%ld)",
53953 (long) arr_idx, (long) old_len));
53954 }
53955 }
53956
53957 /* write_to_array_part: */
53958
53959 /*
53960 * Write to array part?
53961 *
53962 * Note: array abandonding requires a property resize which uses
53963 * 'rechecks' valstack for temporaries and may cause any existing
53964 * valstack pointers to be invalidated. To protect against this,
53965 * tv_obj, tv_key, and tv_val are copies of the original inputs.
53966 */
53967
53968 if (arr_idx != DUK__NO_ARRAY_INDEX &&
53969 DUK_HOBJECT_HAS_ARRAY_PART(orig)) {
53970 if (arr_idx < DUK_HOBJECT_GET_ASIZE(orig)) {
53971 goto no_array_growth;
53972 }
53973
53974 /*
53975 * Array needs to grow, but we don't want it becoming too sparse.
53976 * If it were to become sparse, abandon array part, moving all
53977 * array entries into the entries part (for good).
53978 *
53979 * Since we don't keep track of actual density (used vs. size) of
53980 * the array part, we need to estimate somehow. The check is made
53981 * in two parts:
53982 *
53983 * - Check whether the resize need is small compared to the
53984 * current size (relatively); if so, resize without further
53985 * checking (essentially we assume that the original part is
53986 * "dense" so that the result would be dense enough).
53987 *
53988 * - Otherwise, compute the resize using an actual density
53989 * measurement based on counting the used array entries.
53990 */
53991
53992 DUK_DDD(DUK_DDDPRINT("write to new array requires array resize, decide whether to do a "
53993 "fast resize without abandon check (arr_idx=%ld, old_size=%ld)",
53994 (long) arr_idx, (long) DUK_HOBJECT_GET_ASIZE(orig)));
53995
53996 if (duk__abandon_array_slow_check_required(arr_idx, DUK_HOBJECT_GET_ASIZE(orig))) {
53997 duk_uint32_t old_used;
53998 duk_uint32_t old_size;
53999
54000 DUK_DDD(DUK_DDDPRINT("=> fast check is NOT OK, do slow check for array abandon"));
54001
54002 duk__compute_a_stats(thr, orig, &old_used, &old_size);
54003
54004 DUK_DDD(DUK_DDDPRINT("abandon check, array stats: old_used=%ld, old_size=%ld, arr_idx=%ld",
54005 (long) old_used, (long) old_size, (long) arr_idx));
54006
54007 /* Note: intentionally use approximations to shave a few instructions:
54008 * a_used = old_used (accurate: old_used + 1)
54009 * a_size = arr_idx (accurate: arr_idx + 1)
54010 */
54011 if (duk__abandon_array_density_check(old_used, arr_idx)) {
54012 DUK_DD(DUK_DDPRINT("write to new array entry beyond current length, "
54013 "decided to abandon array part (would become too sparse)"));
54014
54015 /* abandoning requires a props allocation resize and
54016 * 'rechecks' the valstack, invalidating any existing
54017 * valstack value pointers!
54018 */
54019 duk__abandon_array_checked(thr, orig);
54020 DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(orig));
54021
54022 goto write_to_entry_part;
54023 }
54024
54025 DUK_DDD(DUK_DDDPRINT("=> decided to keep array part"));
54026 } else {
54027 DUK_DDD(DUK_DDDPRINT("=> fast resize is OK"));
54028 }
54029
54030 DUK_DD(DUK_DDPRINT("write to new array entry beyond current length, "
54031 "decided to extend current allocation"));
54032
54033 duk__grow_props_for_array_item(thr, orig, arr_idx);
54034
54035 no_array_growth:
54036
54037 /* Note: assume array part is comprehensive, so that either
54038 * the write goes to the array part, or we've abandoned the
54039 * array above (and will not come here).
54040 */
54041
54042 DUK_ASSERT(DUK_HOBJECT_HAS_ARRAY_PART(orig));
54043 DUK_ASSERT(arr_idx < DUK_HOBJECT_GET_ASIZE(orig));
54044
54045 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, orig, arr_idx);
54046 /* prev value must be unused, no decref */
54047 DUK_ASSERT(DUK_TVAL_IS_UNUSED(tv));
54048 DUK_TVAL_SET_TVAL(tv, tv_val);
54049 DUK_TVAL_INCREF(thr, tv);
54050 DUK_DD(DUK_DDPRINT("put to new array entry: %ld -> %!T",
54051 (long) arr_idx, (duk_tval *) tv));
54052
54053 /* Note: array part values are [[Writable]], [[Enumerable]],
54054 * and [[Configurable]] which matches the required attributes
54055 * here.
54056 */
54057 goto entry_updated;
54058 }
54059
54060 write_to_entry_part:
54061
54062 /*
54063 * Write to entry part
54064 */
54065
54066 /* entry allocation updates hash part and increases the key
54067 * refcount; may need a props allocation resize but doesn't
54068 * 'recheck' the valstack.
54069 */
54070 e_idx = duk__alloc_entry_checked(thr, orig, key);
54071 DUK_ASSERT(e_idx >= 0);
54072
54073 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, orig, e_idx);
54074 /* prev value can be garbage, no decref */
54075 DUK_TVAL_SET_TVAL(tv, tv_val);
54076 DUK_TVAL_INCREF(thr, tv);
54077 DUK_HOBJECT_E_SET_FLAGS(thr->heap, orig, e_idx, DUK_PROPDESC_FLAGS_WEC);
54078 goto entry_updated;
54079
54080 entry_updated:
54081
54082 /*
54083 * Possible pending array length update, which must only be done
54084 * if the actual entry write succeeded.
54085 */
54086
54087 if (new_array_length > 0) {
54088 /* Note: zero works as a "no update" marker because the new length
54089 * can never be zero after a new property is written.
54090 */
54091
54092 DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(orig));
54093
54094 DUK_DDD(DUK_DDDPRINT("write successful, pending array length update to: %ld",
54095 (long) new_array_length));
54096
54097 ((duk_harray *) orig)->length = new_array_length;
54098 }
54099
54100 /*
54101 * Arguments exotic behavior not possible for new properties: all
54102 * magically bound properties are initially present in the arguments
54103 * object, and if they are deleted, the binding is also removed from
54104 * parameter map.
54105 */
54106
54107 goto success_no_arguments_exotic;
54108
54109 success_with_arguments_exotic:
54110
54111 /*
54112 * Arguments objects have exotic [[DefineOwnProperty]] which updates
54113 * the internal 'map' of arguments for writes to currently mapped
54114 * arguments. More conretely, writes to mapped arguments generate
54115 * a write to a bound variable.
54116 *
54117 * The [[Put]] algorithm invokes [[DefineOwnProperty]] for existing
54118 * data properties and new properties, but not for existing accessors.
54119 * Hence, in E5 Section 10.6 ([[DefinedOwnProperty]] algorithm), we
54120 * have a Desc with 'Value' (and possibly other properties too), and
54121 * we end up in step 5.b.i.
54122 */
54123
54124 if (arr_idx != DUK__NO_ARRAY_INDEX &&
54125 DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(orig)) {
54126 /* Note: only numbered indices are relevant, so arr_idx fast reject
54127 * is good (this is valid unless there are more than 4**32-1 arguments).
54128 */
54129
54130 DUK_DDD(DUK_DDDPRINT("putprop successful, arguments exotic behavior needed"));
54131
54132 /* Note: we can reuse 'desc' here */
54133
54134 /* XXX: top of stack must contain value, which helper doesn't touch,
54135 * rework to use tv_val directly?
54136 */
54137
54138 duk_push_tval(ctx, tv_val);
54139 (void) duk__check_arguments_map_for_put(thr, orig, key, &desc, throw_flag);
54140 duk_pop(ctx);
54141 }
54142 /* fall thru */
54143
54144 success_no_arguments_exotic:
54145 /* shared exit path now */
54146 DUK_DDD(DUK_DDDPRINT("result: success"));
54147 duk_pop(ctx); /* remove key */
54148 return 1;
54149
54150#if defined(DUK_USE_ES6_PROXY)
54151 fail_proxy_rejected:
54152 DUK_DDD(DUK_DDDPRINT("result: error, proxy rejects"));
54153 if (throw_flag) {
54154 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
54155 }
54156 /* Note: no key on stack */
54157 return 0;
54158#endif
54159
54160 fail_base_primitive:
54161 DUK_DDD(DUK_DDDPRINT("result: error, base primitive"));
54162 if (throw_flag) {
54163#if defined(DUK_USE_PARANOID_ERRORS)
54164 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
54165#else
54166 DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot write property %s of %s",
54167 duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj));
54168#endif
54169 }
54170 duk_pop(ctx); /* remove key */
54171 return 0;
54172
54173 fail_not_extensible:
54174 DUK_DDD(DUK_DDDPRINT("result: error, not extensible"));
54175 if (throw_flag) {
54176 DUK_ERROR_TYPE(thr, DUK_STR_NOT_EXTENSIBLE);
54177 }
54178 duk_pop(ctx); /* remove key */
54179 return 0;
54180
54181 fail_not_writable:
54182 DUK_DDD(DUK_DDDPRINT("result: error, not writable"));
54183 if (throw_flag) {
54184 DUK_ERROR_TYPE(thr, DUK_STR_NOT_WRITABLE);
54185 }
54186 duk_pop(ctx); /* remove key */
54187 return 0;
54188
54189#if defined(DUK_USE_ROM_OBJECTS)
54190 fail_not_writable_no_pop:
54191 DUK_DDD(DUK_DDDPRINT("result: error, not writable"));
54192 if (throw_flag) {
54193 DUK_ERROR_TYPE(thr, DUK_STR_NOT_WRITABLE);
54194 }
54195 return 0;
54196#endif
54197
54198 fail_array_length_partial:
54199 DUK_DD(DUK_DDPRINT("result: error, array length write only partially successful"));
54200 if (throw_flag) {
54201 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
54202 }
54203 duk_pop(ctx); /* remove key */
54204 return 0;
54205
54206 fail_no_setter:
54207 DUK_DDD(DUK_DDDPRINT("result: error, accessor property without setter"));
54208 if (throw_flag) {
54209 DUK_ERROR_TYPE(thr, DUK_STR_SETTER_UNDEFINED);
54210 }
54211 duk_pop(ctx); /* remove key */
54212 return 0;
54213
54214 fail_internal:
54215 DUK_DDD(DUK_DDDPRINT("result: error, internal"));
54216 if (throw_flag) {
54217 DUK_ERROR_INTERNAL(thr);
54218 }
54219 duk_pop(ctx); /* remove key */
54220 return 0;
54221}
54222
54223/*
54224 * Ecmascript compliant [[Delete]](P, Throw).
54225 */
54226
54227DUK_INTERNAL duk_bool_t duk_hobject_delprop_raw(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags) {
54228 duk_propdesc desc;
54229 duk_tval *tv;
54230 duk_uint32_t arr_idx;
54231 duk_bool_t throw_flag;
54232 duk_bool_t force_flag;
54233
54234 throw_flag = (flags & DUK_DELPROP_FLAG_THROW);
54235 force_flag = (flags & DUK_DELPROP_FLAG_FORCE);
54236
54237 DUK_DDD(DUK_DDDPRINT("delprop_raw: thr=%p, obj=%p, key=%p, throw=%ld, force=%ld (obj -> %!O, key -> %!O)",
54238 (void *) thr, (void *) obj, (void *) key, (long) throw_flag, (long) force_flag,
54239 (duk_heaphdr *) obj, (duk_heaphdr *) key));
54240
54241 DUK_ASSERT(thr != NULL);
54242 DUK_ASSERT(thr->heap != NULL);
54243 DUK_ASSERT(obj != NULL);
54244 DUK_ASSERT(key != NULL);
54245
54246 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
54247
54248 arr_idx = DUK_HSTRING_GET_ARRIDX_FAST(key);
54249
54250 /* 0 = don't push current value */
54251 if (!duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */
54252 DUK_DDD(DUK_DDDPRINT("property not found, succeed always"));
54253 goto success;
54254 }
54255
54256#if defined(DUK_USE_ROM_OBJECTS)
54257 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
54258 DUK_DD(DUK_DDPRINT("attempt to delprop on read-only target object"));
54259 goto fail_not_configurable;
54260 }
54261#endif
54262
54263 if ((desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) == 0 && !force_flag) {
54264 goto fail_not_configurable;
54265 }
54266 if (desc.a_idx < 0 && desc.e_idx < 0) {
54267 /* Currently there are no deletable virtual properties, but
54268 * with force_flag we might attempt to delete one.
54269 */
54270 DUK_DD(DUK_DDPRINT("delete failed: property found, force flag, but virtual (and implicitly non-configurable)"));
54271 goto fail_virtual;
54272 }
54273
54274 if (desc.a_idx >= 0) {
54275 DUK_ASSERT(desc.e_idx < 0);
54276
54277 tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, desc.a_idx);
54278 DUK_TVAL_SET_UNUSED_UPDREF(thr, tv); /* side effects */
54279 goto success;
54280 } else {
54281 DUK_ASSERT(desc.a_idx < 0);
54282
54283 /* remove hash entry (no decref) */
54284#if defined(DUK_USE_HOBJECT_HASH_PART)
54285 if (desc.h_idx >= 0) {
54286 duk_uint32_t *h_base = DUK_HOBJECT_H_GET_BASE(thr->heap, obj);
54287
54288 DUK_DDD(DUK_DDDPRINT("removing hash entry at h_idx %ld", (long) desc.h_idx));
54289 DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(obj) > 0);
54290 DUK_ASSERT((duk_uint32_t) desc.h_idx < DUK_HOBJECT_GET_HSIZE(obj));
54291 h_base[desc.h_idx] = DUK__HASH_DELETED;
54292 } else {
54293 DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(obj) == 0);
54294 }
54295#else
54296 DUK_ASSERT(DUK_HOBJECT_GET_HSIZE(obj) == 0);
54297#endif
54298
54299 /* Remove value. This requires multiple writes so avoid side
54300 * effects via no-refzero macros so that e_idx is not
54301 * invalidated.
54302 */
54303 DUK_DDD(DUK_DDDPRINT("before removing value, e_idx %ld, key %p, key at slot %p",
54304 (long) desc.e_idx, (void *) key, (void *) DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx)));
54305 DUK_DDD(DUK_DDDPRINT("removing value at e_idx %ld", (long) desc.e_idx));
54306 if (DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, desc.e_idx)) {
54307 duk_hobject *tmp;
54308
54309 tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, desc.e_idx);
54310 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, desc.e_idx, NULL);
54311 DUK_UNREF(tmp);
54312 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp);
54313
54314 tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, desc.e_idx);
54315 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, desc.e_idx, NULL);
54316 DUK_UNREF(tmp);
54317 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp);
54318 } else {
54319 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, desc.e_idx);
54320 DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv);
54321 }
54322#if 0
54323 /* Not strictly necessary because if key == NULL, flag MUST be ignored. */
54324 DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, desc.e_idx, 0);
54325#endif
54326
54327 /* Remove key. */
54328 DUK_DDD(DUK_DDDPRINT("before removing key, e_idx %ld, key %p, key at slot %p",
54329 (long) desc.e_idx, (void *) key, (void *) DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx)));
54330 DUK_DDD(DUK_DDDPRINT("removing key at e_idx %ld", (long) desc.e_idx));
54331 DUK_ASSERT(key == DUK_HOBJECT_E_GET_KEY(thr->heap, obj, desc.e_idx));
54332 DUK_HOBJECT_E_SET_KEY(thr->heap, obj, desc.e_idx, NULL);
54333 DUK_HSTRING_DECREF_NORZ(thr, key);
54334
54335 /* Trigger refzero side effects only when we're done as a
54336 * finalizer might operate on the object and affect the
54337 * e_idx we're supposed to use.
54338 */
54339 DUK_REFZERO_CHECK_SLOW(thr);
54340 goto success;
54341 }
54342
54343 DUK_UNREACHABLE();
54344
54345 success:
54346 /*
54347 * Argument exotic [[Delete]] behavior (E5 Section 10.6) is
54348 * a post-check, keeping arguments internal 'map' in sync with
54349 * any successful deletes (note that property does not need to
54350 * exist for delete to 'succeed').
54351 *
54352 * Delete key from 'map'. Since 'map' only contains array index
54353 * keys, we can use arr_idx for a fast skip.
54354 */
54355
54356 DUK_DDD(DUK_DDDPRINT("delete successful, check for arguments exotic behavior"));
54357
54358 if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj)) {
54359 /* Note: only numbered indices are relevant, so arr_idx fast reject
54360 * is good (this is valid unless there are more than 4**32-1 arguments).
54361 */
54362
54363 DUK_DDD(DUK_DDDPRINT("delete successful, arguments exotic behavior needed"));
54364
54365 /* Note: we can reuse 'desc' here */
54366 (void) duk__check_arguments_map_for_delete(thr, obj, key, &desc);
54367 }
54368
54369 DUK_DDD(DUK_DDDPRINT("delete successful"));
54370 return 1;
54371
54372 fail_virtual: /* just use the same "not configurable" error message */
54373 fail_not_configurable:
54374 DUK_DDD(DUK_DDDPRINT("delete failed: property found, not configurable"));
54375
54376 if (throw_flag) {
54377 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
54378 }
54379 return 0;
54380}
54381
54382/*
54383 * DELPROP: Ecmascript property deletion.
54384 */
54385
54386DUK_INTERNAL duk_bool_t duk_hobject_delprop(duk_hthread *thr, duk_tval *tv_obj, duk_tval *tv_key, duk_bool_t throw_flag) {
54387 duk_context *ctx = (duk_context *) thr;
54388 duk_hstring *key = NULL;
54389#if defined(DUK_USE_ES6_PROXY)
54390 duk_propdesc desc;
54391#endif
54392 duk_int_t entry_top;
54393 duk_uint32_t arr_idx = DUK__NO_ARRAY_INDEX;
54394 duk_bool_t rc;
54395
54396 DUK_DDD(DUK_DDDPRINT("delprop: thr=%p, obj=%p, key=%p (obj -> %!T, key -> %!T)",
54397 (void *) thr, (void *) tv_obj, (void *) tv_key,
54398 (duk_tval *) tv_obj, (duk_tval *) tv_key));
54399
54400 DUK_ASSERT(ctx != NULL);
54401 DUK_ASSERT(thr != NULL);
54402 DUK_ASSERT(thr->heap != NULL);
54403 DUK_ASSERT(tv_obj != NULL);
54404 DUK_ASSERT(tv_key != NULL);
54405
54406 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
54407
54408 /* Storing the entry top is cheaper here to ensure stack is correct at exit,
54409 * as there are several paths out.
54410 */
54411 entry_top = duk_get_top(ctx);
54412
54413 if (DUK_TVAL_IS_UNDEFINED(tv_obj) ||
54414 DUK_TVAL_IS_NULL(tv_obj)) {
54415 DUK_DDD(DUK_DDDPRINT("base object is undefined or null -> reject"));
54416 goto fail_invalid_base_uncond;
54417 }
54418
54419 duk_push_tval(ctx, tv_obj);
54420 duk_push_tval(ctx, tv_key);
54421
54422 tv_obj = DUK_GET_TVAL_NEGIDX(ctx, -2);
54423 if (DUK_TVAL_IS_OBJECT(tv_obj)) {
54424 duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv_obj);
54425 DUK_ASSERT(obj != NULL);
54426
54427#if defined(DUK_USE_ES6_PROXY)
54428 if (DUK_UNLIKELY(DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(obj))) {
54429 duk_hobject *h_target;
54430 duk_bool_t tmp_bool;
54431
54432 /* Note: proxy handling must happen before key is string coerced. */
54433
54434 if (duk__proxy_check_prop(thr, obj, DUK_STRIDX_DELETE_PROPERTY, tv_key, &h_target)) {
54435 /* -> [ ... trap handler ] */
54436 DUK_DDD(DUK_DDDPRINT("-> proxy object 'deleteProperty' for key %!T", (duk_tval *) tv_key));
54437 duk_push_hobject(ctx, h_target); /* target */
54438 duk_push_tval(ctx, tv_key); /* P */
54439 duk_call_method(ctx, 2 /*nargs*/);
54440 tmp_bool = duk_to_boolean(ctx, -1);
54441 duk_pop(ctx);
54442 if (!tmp_bool) {
54443 goto fail_proxy_rejected; /* retval indicates delete failed */
54444 }
54445
54446 /* Target object must be checked for a conflicting
54447 * non-configurable property.
54448 */
54449 arr_idx = duk__push_tval_to_property_key(ctx, tv_key, &key);
54450 DUK_ASSERT(key != NULL);
54451
54452 if (duk__get_own_propdesc_raw(thr, h_target, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */
54453 duk_small_int_t desc_reject;
54454
54455 DUK_DDD(DUK_DDDPRINT("proxy 'deleteProperty': target has matching property %!O, check for "
54456 "conflicting property; desc.flags=0x%08lx, "
54457 "desc.get=%p, desc.set=%p",
54458 (duk_heaphdr *) key, (unsigned long) desc.flags,
54459 (void *) desc.get, (void *) desc.set));
54460
54461 desc_reject = !(desc.flags & DUK_PROPDESC_FLAG_CONFIGURABLE);
54462 if (desc_reject) {
54463 /* unconditional */
54464 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
54465 }
54466 }
54467 rc = 1; /* success */
54468 goto done_rc;
54469 }
54470
54471 obj = h_target; /* resume delete to target */
54472 }
54473#endif /* DUK_USE_ES6_PROXY */
54474
54475 arr_idx = duk__to_property_key(ctx, -1, &key);
54476 DUK_ASSERT(key != NULL);
54477
54478 rc = duk_hobject_delprop_raw(thr, obj, key, throw_flag ? DUK_DELPROP_FLAG_THROW : 0);
54479 goto done_rc;
54480 } else if (DUK_TVAL_IS_STRING(tv_obj)) {
54481 /* String has .length and array index virtual properties
54482 * which can't be deleted. No need for a symbol check;
54483 * no offending virtual symbols exist.
54484 */
54485 /* XXX: unnecessary string coercion for array indices,
54486 * intentional to keep small.
54487 */
54488 duk_hstring *h = DUK_TVAL_GET_STRING(tv_obj);
54489 DUK_ASSERT(h != NULL);
54490
54491 arr_idx = duk__to_property_key(ctx, -1, &key);
54492 DUK_ASSERT(key != NULL);
54493
54494 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
54495 goto fail_not_configurable;
54496 }
54497
54498 if (arr_idx != DUK__NO_ARRAY_INDEX &&
54499 arr_idx < DUK_HSTRING_GET_CHARLEN(h)) {
54500 goto fail_not_configurable;
54501 }
54502 } else if (DUK_TVAL_IS_BUFFER(tv_obj)) {
54503 /* XXX: unnecessary string coercion for array indices,
54504 * intentional to keep small; some overlap with string
54505 * handling.
54506 */
54507 duk_hbuffer *h = DUK_TVAL_GET_BUFFER(tv_obj);
54508 DUK_ASSERT(h != NULL);
54509
54510 arr_idx = duk__to_property_key(ctx, -1, &key);
54511 DUK_ASSERT(key != NULL);
54512
54513 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
54514 goto fail_not_configurable;
54515 }
54516
54517 if (arr_idx != DUK__NO_ARRAY_INDEX &&
54518 arr_idx < DUK_HBUFFER_GET_SIZE(h)) {
54519 goto fail_not_configurable;
54520 }
54521 } else if (DUK_TVAL_IS_LIGHTFUNC(tv_obj)) {
54522 /* Lightfunc virtual properties are non-configurable, so
54523 * reject if match any of them.
54524 */
54525
54526 arr_idx = duk__to_property_key(ctx, -1, &key);
54527 DUK_ASSERT(key != NULL);
54528
54529 if (duk__key_is_lightfunc_ownprop(thr, key)) {
54530 goto fail_not_configurable;
54531 }
54532 }
54533
54534 /* non-object base, no offending virtual property */
54535 rc = 1;
54536 goto done_rc;
54537
54538 done_rc:
54539 duk_set_top(ctx, entry_top);
54540 return rc;
54541
54542 fail_invalid_base_uncond:
54543 /* Note: unconditional throw */
54544 DUK_ASSERT(duk_get_top(ctx) == entry_top);
54545#if defined(DUK_USE_PARANOID_ERRORS)
54546 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_BASE);
54547#else
54548 DUK_ERROR_FMT2(thr, DUK_ERR_TYPE_ERROR, "cannot delete property %s of %s",
54549 duk_push_string_tval_readable(ctx, tv_key), duk_push_string_tval_readable(ctx, tv_obj));
54550#endif
54551 return 0;
54552
54553#if defined(DUK_USE_ES6_PROXY)
54554 fail_proxy_rejected:
54555 if (throw_flag) {
54556 DUK_ERROR_TYPE(thr, DUK_STR_PROXY_REJECTED);
54557 }
54558 duk_set_top(ctx, entry_top);
54559 return 0;
54560#endif
54561
54562 fail_not_configurable:
54563 if (throw_flag) {
54564 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
54565 }
54566 duk_set_top(ctx, entry_top);
54567 return 0;
54568}
54569
54570/*
54571 * Internal helper to define a property with specific flags, ignoring
54572 * normal semantics such as extensibility, write protection etc.
54573 * Overwrites any existing value and attributes unless caller requests
54574 * that value only be updated if it doesn't already exists.
54575 *
54576 * Does not support:
54577 * - virtual properties (error if write attempted)
54578 * - getter/setter properties (error if write attempted)
54579 * - non-default (!= WEC) attributes for array entries (error if attempted)
54580 * - array abandoning: if array part exists, it is always extended
54581 * - array 'length' updating
54582 *
54583 * Stack: [... in_val] -> []
54584 *
54585 * Used for e.g. built-in initialization and environment record
54586 * operations.
54587 */
54588
54589DUK_INTERNAL void duk_hobject_define_property_internal(duk_hthread *thr, duk_hobject *obj, duk_hstring *key, duk_small_uint_t flags) {
54590 duk_context *ctx = (duk_context *) thr;
54591 duk_propdesc desc;
54592 duk_uint32_t arr_idx;
54593 duk_int_t e_idx;
54594 duk_tval *tv1 = NULL;
54595 duk_tval *tv2 = NULL;
54596 duk_small_uint_t propflags = flags & DUK_PROPDESC_FLAGS_MASK; /* mask out flags not actually stored */
54597
54598 DUK_DDD(DUK_DDDPRINT("define new property (internal): thr=%p, obj=%!O, key=%!O, flags=0x%02lx, val=%!T",
54599 (void *) thr, (duk_heaphdr *) obj, (duk_heaphdr *) key,
54600 (unsigned long) flags, (duk_tval *) duk_get_tval(ctx, -1)));
54601
54602 DUK_ASSERT(thr != NULL);
54603 DUK_ASSERT(thr->heap != NULL);
54604 DUK_ASSERT(obj != NULL);
54605 DUK_ASSERT(key != NULL);
54606 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
54607 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
54608 DUK_ASSERT(duk_is_valid_index(ctx, -1)); /* contains value */
54609
54610 arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
54611
54612 if (duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &desc, 0 /*flags*/)) { /* don't push value */
54613 if (desc.e_idx >= 0) {
54614 if (flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) {
54615 DUK_DDD(DUK_DDDPRINT("property already exists in the entry part -> skip as requested"));
54616 goto pop_exit;
54617 }
54618 DUK_DDD(DUK_DDDPRINT("property already exists in the entry part -> update value and attributes"));
54619 if (DUK_UNLIKELY(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, desc.e_idx))) {
54620 DUK_D(DUK_DPRINT("existing property is an accessor, not supported"));
54621 goto error_internal;
54622 }
54623
54624 DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, desc.e_idx, propflags);
54625 tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, desc.e_idx);
54626 } else if (desc.a_idx >= 0) {
54627 if (flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) {
54628 DUK_DDD(DUK_DDDPRINT("property already exists in the array part -> skip as requested"));
54629 goto pop_exit;
54630 }
54631 DUK_DDD(DUK_DDDPRINT("property already exists in the array part -> update value (assert attributes)"));
54632 if (propflags != DUK_PROPDESC_FLAGS_WEC) {
54633 DUK_D(DUK_DPRINT("existing property in array part, but propflags not WEC (0x%02lx)",
54634 (unsigned long) propflags));
54635 goto error_internal;
54636 }
54637
54638 tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, desc.a_idx);
54639 } else {
54640 if (flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) {
54641 DUK_DDD(DUK_DDDPRINT("property already exists but is virtual -> skip as requested"));
54642 goto pop_exit;
54643 }
54644 if (key == DUK_HTHREAD_STRING_LENGTH(thr) && DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
54645 duk_uint32_t new_len;
54646#if defined(DUK_USE_DEBUG)
54647 duk_uint32_t prev_len;
54648 prev_len = ((duk_harray *) obj)->length;
54649#endif
54650 new_len = duk__to_new_array_length_checked(thr, DUK_GET_TVAL_NEGIDX(ctx, -1));
54651 ((duk_harray *) obj)->length = new_len;
54652 DUK_D(DUK_DPRINT("internal define property for array .length: %ld -> %ld",
54653 (long) prev_len, (long) ((duk_harray *) obj)->length));
54654 goto pop_exit;
54655 }
54656 DUK_DD(DUK_DDPRINT("property already exists but is virtual -> failure"));
54657 goto error_virtual;
54658 }
54659
54660 goto write_value;
54661 }
54662
54663 if (DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
54664 if (arr_idx != DUK__NO_ARRAY_INDEX) {
54665 DUK_DDD(DUK_DDDPRINT("property does not exist, object has array part -> possibly extend array part and write value (assert attributes)"));
54666 DUK_ASSERT(propflags == DUK_PROPDESC_FLAGS_WEC);
54667
54668 /* always grow the array, no sparse / abandon support here */
54669 if (arr_idx >= DUK_HOBJECT_GET_ASIZE(obj)) {
54670 duk__grow_props_for_array_item(thr, obj, arr_idx);
54671 }
54672
54673 DUK_ASSERT(arr_idx < DUK_HOBJECT_GET_ASIZE(obj));
54674 tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx);
54675 goto write_value;
54676 }
54677 }
54678
54679 DUK_DDD(DUK_DDDPRINT("property does not exist, object belongs in entry part -> allocate new entry and write value and attributes"));
54680 e_idx = duk__alloc_entry_checked(thr, obj, key); /* increases key refcount */
54681 DUK_ASSERT(e_idx >= 0);
54682 DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, e_idx, propflags);
54683 tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx);
54684 /* new entry: previous value is garbage; set to undefined to share write_value */
54685 DUK_TVAL_SET_UNDEFINED(tv1);
54686 goto write_value;
54687
54688 write_value:
54689 /* tv1 points to value storage */
54690
54691 tv2 = duk_require_tval(ctx, -1); /* late lookup, avoid side effects */
54692 DUK_DDD(DUK_DDDPRINT("writing/updating value: %!T -> %!T",
54693 (duk_tval *) tv1, (duk_tval *) tv2));
54694
54695 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
54696 goto pop_exit;
54697
54698 pop_exit:
54699 duk_pop(ctx); /* remove in_val */
54700 return;
54701
54702 error_virtual: /* share error message */
54703 error_internal:
54704 DUK_ERROR_INTERNAL(thr);
54705 return;
54706}
54707
54708/*
54709 * Fast path for defining array indexed values without interning the key.
54710 * This is used by e.g. code for Array prototype and traceback creation so
54711 * must avoid interning.
54712 */
54713
54714DUK_INTERNAL void duk_hobject_define_property_internal_arridx(duk_hthread *thr, duk_hobject *obj, duk_uarridx_t arr_idx, duk_small_uint_t flags) {
54715 duk_context *ctx = (duk_context *) thr;
54717 duk_tval *tv1, *tv2;
54718
54719 DUK_DDD(DUK_DDDPRINT("define new property (internal) arr_idx fast path: thr=%p, obj=%!O, "
54720 "arr_idx=%ld, flags=0x%02lx, val=%!T",
54721 (void *) thr, obj, (long) arr_idx, (unsigned long) flags,
54722 (duk_tval *) duk_get_tval(ctx, -1)));
54723
54724 DUK_ASSERT(thr != NULL);
54725 DUK_ASSERT(thr->heap != NULL);
54726 DUK_ASSERT(obj != NULL);
54727 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj));
54728
54729 if (DUK_HOBJECT_HAS_ARRAY_PART(obj) &&
54730 arr_idx != DUK__NO_ARRAY_INDEX &&
54731 flags == DUK_PROPDESC_FLAGS_WEC) {
54732 DUK_ASSERT((flags & DUK_PROPDESC_FLAG_NO_OVERWRITE) == 0); /* covered by comparison */
54733
54734 DUK_DDD(DUK_DDDPRINT("define property to array part (property may or may not exist yet)"));
54735
54736 /* always grow the array, no sparse / abandon support here */
54737 if (arr_idx >= DUK_HOBJECT_GET_ASIZE(obj)) {
54738 duk__grow_props_for_array_item(thr, obj, arr_idx);
54739 }
54740
54741 DUK_ASSERT(arr_idx < DUK_HOBJECT_GET_ASIZE(obj));
54742 tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, arr_idx);
54743 tv2 = duk_require_tval(ctx, -1);
54744
54745 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
54746
54747 duk_pop(ctx); /* [ ...val ] -> [ ... ] */
54748 return;
54749 }
54750
54751 DUK_DDD(DUK_DDDPRINT("define property fast path didn't work, use slow path"));
54752
54753 key = duk_push_uint_to_hstring(ctx, (duk_uint_t) arr_idx);
54754 DUK_ASSERT(key != NULL);
54755 duk_insert(ctx, -2); /* [ ... val key ] -> [ ... key val ] */
54756
54757 duk_hobject_define_property_internal(thr, obj, key, flags);
54758
54759 duk_pop(ctx); /* [ ... key ] -> [ ... ] */
54760}
54761
54762/*
54763 * Internal helpers for managing object 'length'
54764 */
54765
54766DUK_INTERNAL duk_size_t duk_hobject_get_length(duk_hthread *thr, duk_hobject *obj) {
54767 duk_context *ctx = (duk_context *) thr;
54768 duk_double_t val;
54769
54770 DUK_ASSERT_CTX_VALID(ctx);
54771 DUK_ASSERT(obj != NULL);
54772
54773 /* Fast path for Arrays. */
54774 if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
54775 return ((duk_harray *) obj)->length;
54776 }
54777
54778 /* Slow path, .length can be e.g. accessor, obj can be a Proxy, etc. */
54779 duk_push_hobject(ctx, obj);
54780 duk_push_hstring_stridx(ctx, DUK_STRIDX_LENGTH);
54781 (void) duk_hobject_getprop(thr,
54782 DUK_GET_TVAL_NEGIDX(ctx, -2),
54783 DUK_GET_TVAL_NEGIDX(ctx, -1));
54784 val = duk_to_number_m1(ctx);
54785 duk_pop_3(ctx);
54786
54787 /* This isn't part of Ecmascript semantics; return a value within
54788 * duk_size_t range, or 0 otherwise.
54789 */
54790 if (val >= 0.0 && val <= (duk_double_t) DUK_SIZE_MAX) {
54791 return (duk_size_t) val;
54792 }
54793 return 0;
54794}
54795
54796/*
54797 * Object.getOwnPropertyDescriptor() (E5 Sections 15.2.3.3, 8.10.4)
54798 *
54799 * [ ... key ] -> [ ... desc/undefined ]
54800 */
54801
54802DUK_INTERNAL void duk_hobject_object_get_own_property_descriptor(duk_context *ctx, duk_idx_t obj_idx) {
54803 duk_hthread *thr = (duk_hthread *) ctx;
54804 duk_hobject *obj;
54806 duk_propdesc pd;
54807 duk_bool_t rc;
54808
54809 DUK_ASSERT(ctx != NULL);
54810 DUK_ASSERT(thr != NULL);
54811 DUK_ASSERT(thr->heap != NULL);
54812
54813 obj = duk_require_hobject_promote_mask(ctx, obj_idx, DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
54814 key = duk_to_property_key_hstring(ctx, -1);
54815 DUK_ASSERT(key != NULL);
54816
54817 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
54818
54819 rc = duk_hobject_get_own_propdesc(thr, obj, key, &pd, DUK_GETDESC_FLAG_PUSH_VALUE);
54820 if (!rc) {
54821 duk_push_undefined(ctx);
54822 duk_remove_m2(ctx);
54823 return;
54824 }
54825
54826 duk_push_object(ctx);
54827
54828 /* [ ... key value desc ] */
54829
54830 if (DUK_PROPDESC_IS_ACCESSOR(&pd)) {
54831 /* If a setter/getter is missing (undefined), the descriptor must
54832 * still have the property present with the value 'undefined'.
54833 */
54834 if (pd.get) {
54835 duk_push_hobject(ctx, pd.get);
54836 } else {
54837 duk_push_undefined(ctx);
54838 }
54839 duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_GET);
54840 if (pd.set) {
54841 duk_push_hobject(ctx, pd.set);
54842 } else {
54843 duk_push_undefined(ctx);
54844 }
54845 duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_SET);
54846 } else {
54847 duk_dup_m2(ctx);
54848 duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_VALUE);
54849 duk_push_boolean(ctx, DUK_PROPDESC_IS_WRITABLE(&pd));
54850 duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_WRITABLE);
54851 }
54852 duk_push_boolean(ctx, DUK_PROPDESC_IS_ENUMERABLE(&pd));
54853 duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_ENUMERABLE);
54854 duk_push_boolean(ctx, DUK_PROPDESC_IS_CONFIGURABLE(&pd));
54855 duk_put_prop_stridx_short(ctx, -2, DUK_STRIDX_CONFIGURABLE);
54856
54857 /* [ ... key value desc ] */
54858
54859 duk_replace(ctx, -3);
54860 duk_pop(ctx); /* -> [ ... desc ] */
54861}
54862
54863/*
54864 * NormalizePropertyDescriptor() related helper.
54865 *
54866 * Internal helper which validates and normalizes a property descriptor
54867 * represented as an Ecmascript object (e.g. argument to defineProperty()).
54868 * The output of this conversion is a set of defprop_flags and possibly
54869 * some values pushed on the value stack to (1) ensure borrowed pointers
54870 * remain valid, and (2) avoid unnecessary pops for footprint reasons.
54871 * Caller must manage stack top carefully because the number of values
54872 * pushed depends on the input property descriptor.
54873 *
54874 * The original descriptor object must not be altered in the process.
54875 */
54876
54877/* XXX: very basic optimization -> duk_get_prop_stridx_top */
54878
54879DUK_INTERNAL
54880void duk_hobject_prepare_property_descriptor(duk_context *ctx,
54881 duk_idx_t idx_in,
54882 duk_uint_t *out_defprop_flags,
54883 duk_idx_t *out_idx_value,
54884 duk_hobject **out_getter,
54885 duk_hobject **out_setter) {
54886 duk_hthread *thr = (duk_hthread *) ctx;
54887 duk_idx_t idx_value = -1;
54888 duk_hobject *getter = NULL;
54889 duk_hobject *setter = NULL;
54890 duk_bool_t is_data_desc = 0;
54891 duk_bool_t is_acc_desc = 0;
54892 duk_uint_t defprop_flags = 0;
54893
54894 DUK_ASSERT(ctx != NULL);
54895 DUK_ASSERT(out_defprop_flags != NULL);
54896 DUK_ASSERT(out_idx_value != NULL);
54897 DUK_ASSERT(out_getter != NULL);
54898 DUK_ASSERT(out_setter != NULL);
54899 DUK_ASSERT(idx_in <= 0x7fffL); /* short variants would be OK, but not used to avoid shifts */
54900
54901 /* Must be an object, otherwise TypeError (E5.1 Section 8.10.5, step 1). */
54902 idx_in = duk_require_normalize_index(ctx, idx_in);
54903 (void) duk_require_hobject(ctx, idx_in);
54904
54905 /* The coercion order must match the ToPropertyDescriptor() algorithm
54906 * so that side effects in coercion happen in the correct order.
54907 * (This order also happens to be compatible with duk_def_prop(),
54908 * although it doesn't matter in practice.)
54909 */
54910
54911 if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_VALUE)) {
54912 is_data_desc = 1;
54913 defprop_flags |= DUK_DEFPROP_HAVE_VALUE;
54914 idx_value = duk_get_top_index(ctx);
54915 }
54916
54917 if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_WRITABLE)) {
54918 is_data_desc = 1;
54919 if (duk_to_boolean(ctx, -1)) {
54920 defprop_flags |= DUK_DEFPROP_HAVE_WRITABLE | DUK_DEFPROP_WRITABLE;
54921 } else {
54922 defprop_flags |= DUK_DEFPROP_HAVE_WRITABLE;
54923 }
54924 }
54925
54926 if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_GET)) {
54927 duk_tval *tv = duk_require_tval(ctx, -1);
54928 duk_hobject *h_get;
54929
54930 if (DUK_TVAL_IS_UNDEFINED(tv)) {
54931 /* undefined is accepted */
54932 DUK_ASSERT(getter == NULL);
54933 } else {
54934 /* NOTE: lightfuncs are coerced to full functions because
54935 * lightfuncs don't fit into a property value slot. This
54936 * has some side effects, see test-dev-lightfunc-accessor.js.
54937 */
54938 h_get = duk_get_hobject_promote_lfunc(ctx, -1);
54939 if (h_get == NULL || !DUK_HOBJECT_IS_CALLABLE(h_get)) {
54940 goto type_error;
54941 }
54942 getter = h_get;
54943 }
54944 is_acc_desc = 1;
54945 defprop_flags |= DUK_DEFPROP_HAVE_GETTER;
54946 }
54947
54948 if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_SET)) {
54949 duk_tval *tv = duk_require_tval(ctx, -1);
54950 duk_hobject *h_set;
54951
54952 if (DUK_TVAL_IS_UNDEFINED(tv)) {
54953 /* undefined is accepted */
54954 DUK_ASSERT(setter == NULL);
54955 } else {
54956 /* NOTE: lightfuncs are coerced to full functions because
54957 * lightfuncs don't fit into a property value slot. This
54958 * has some side effects, see test-dev-lightfunc-accessor.js.
54959 */
54960 h_set = duk_get_hobject_promote_lfunc(ctx, -1);
54961 if (h_set == NULL || !DUK_HOBJECT_IS_CALLABLE(h_set)) {
54962 goto type_error;
54963 }
54964 setter = h_set;
54965 }
54966 is_acc_desc = 1;
54967 defprop_flags |= DUK_DEFPROP_HAVE_SETTER;
54968 }
54969
54970 if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_ENUMERABLE)) {
54971 if (duk_to_boolean(ctx, -1)) {
54972 defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_ENUMERABLE;
54973 } else {
54974 defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE;
54975 }
54976 }
54977
54978 if (duk_get_prop_stridx(ctx, idx_in, DUK_STRIDX_CONFIGURABLE)) {
54979 if (duk_to_boolean(ctx, -1)) {
54980 defprop_flags |= DUK_DEFPROP_HAVE_CONFIGURABLE | DUK_DEFPROP_CONFIGURABLE;
54981 } else {
54982 defprop_flags |= DUK_DEFPROP_HAVE_CONFIGURABLE;
54983 }
54984 }
54985
54986 if (is_data_desc && is_acc_desc) {
54987 goto type_error;
54988 }
54989
54990 *out_defprop_flags = defprop_flags;
54991 *out_idx_value = idx_value;
54992 *out_getter = getter;
54993 *out_setter = setter;
54994
54995 /* [ ... [multiple values] ] */
54996 return;
54997
54998 type_error:
54999 DUK_ERROR_TYPE(thr, DUK_STR_INVALID_DESCRIPTOR);
55000}
55001
55002/*
55003 * Object.defineProperty() related helper (E5 Section 15.2.3.6).
55004 * Also handles ES2015 Reflect.defineProperty().
55005 *
55006 * Inlines all [[DefineOwnProperty]] exotic behaviors.
55007 *
55008 * Note: Ecmascript compliant [[DefineOwnProperty]](P, Desc, Throw) is not
55009 * implemented directly, but Object.defineProperty() serves its purpose.
55010 * We don't need the [[DefineOwnProperty]] internally and we don't have a
55011 * property descriptor with 'missing values' so it's easier to avoid it
55012 * entirely.
55013 *
55014 * Note: this is only called for actual objects, not primitive values.
55015 * This must support virtual properties for full objects (e.g. Strings)
55016 * but not for plain values (e.g. strings). Lightfuncs, even though
55017 * primitive in a sense, are treated like objects and accepted as target
55018 * values.
55019 */
55020
55021/* XXX: this is a major target for size optimization */
55022DUK_INTERNAL
55023duk_bool_t duk_hobject_define_property_helper(duk_context *ctx,
55024 duk_uint_t defprop_flags,
55025 duk_hobject *obj,
55027 duk_idx_t idx_value,
55028 duk_hobject *get,
55029 duk_hobject *set,
55030 duk_bool_t throw_flag) {
55031 duk_hthread *thr = (duk_hthread *) ctx;
55032 duk_uint32_t arr_idx;
55033 duk_tval tv;
55034 duk_bool_t has_enumerable;
55035 duk_bool_t has_configurable;
55036 duk_bool_t has_writable;
55037 duk_bool_t has_value;
55038 duk_bool_t has_get;
55039 duk_bool_t has_set;
55040 duk_bool_t is_enumerable;
55041 duk_bool_t is_configurable;
55042 duk_bool_t is_writable;
55043 duk_bool_t force_flag;
55044 duk_small_uint_t new_flags;
55045 duk_propdesc curr;
55046 duk_uint32_t arridx_new_array_length; /* != 0 => post-update for array 'length' (used when key is an array index) */
55047 duk_uint32_t arrlen_old_len;
55048 duk_uint32_t arrlen_new_len;
55049 duk_bool_t pending_write_protect;
55050
55051 DUK_ASSERT(thr != NULL);
55052 DUK_ASSERT(thr->heap != NULL);
55053 DUK_ASSERT(ctx != NULL);
55054 DUK_ASSERT(obj != NULL);
55055 DUK_ASSERT(key != NULL);
55056 /* idx_value may be < 0 (no value), set and get may be NULL */
55057
55058 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
55059
55060 /* All the flags fit in 16 bits, so will fit into duk_bool_t. */
55061
55062 has_writable = (defprop_flags & DUK_DEFPROP_HAVE_WRITABLE);
55063 has_enumerable = (defprop_flags & DUK_DEFPROP_HAVE_ENUMERABLE);
55064 has_configurable = (defprop_flags & DUK_DEFPROP_HAVE_CONFIGURABLE);
55065 has_value = (defprop_flags & DUK_DEFPROP_HAVE_VALUE);
55066 has_get = (defprop_flags & DUK_DEFPROP_HAVE_GETTER);
55067 has_set = (defprop_flags & DUK_DEFPROP_HAVE_SETTER);
55068 is_writable = (defprop_flags & DUK_DEFPROP_WRITABLE);
55069 is_enumerable = (defprop_flags & DUK_DEFPROP_ENUMERABLE);
55070 is_configurable = (defprop_flags & DUK_DEFPROP_CONFIGURABLE);
55071 force_flag = (defprop_flags & DUK_DEFPROP_FORCE);
55072
55073 arr_idx = DUK_HSTRING_GET_ARRIDX_SLOW(key);
55074
55075 arridx_new_array_length = 0;
55076 pending_write_protect = 0;
55077 arrlen_old_len = 0;
55078 arrlen_new_len = 0;
55079
55080 DUK_DDD(DUK_DDDPRINT("has_enumerable=%ld is_enumerable=%ld "
55081 "has_configurable=%ld is_configurable=%ld "
55082 "has_writable=%ld is_writable=%ld "
55083 "has_value=%ld value=%!T "
55084 "has_get=%ld get=%p=%!O "
55085 "has_set=%ld set=%p=%!O "
55086 "arr_idx=%ld throw_flag=!%ld",
55087 (long) has_enumerable, (long) is_enumerable,
55088 (long) has_configurable, (long) is_configurable,
55089 (long) has_writable, (long) is_writable,
55090 (long) has_value, (duk_tval *) (idx_value >= 0 ? duk_get_tval(ctx, idx_value) : NULL),
55091 (long) has_get, (void *) get, (duk_heaphdr *) get,
55092 (long) has_set, (void *) set, (duk_heaphdr *) set,
55093 (long) arr_idx, (long) throw_flag));
55094
55095 /*
55096 * Array exotic behaviors can be implemented at this point. The local variables
55097 * are essentially a 'value copy' of the input descriptor (Desc), which is modified
55098 * by the Array [[DefineOwnProperty]] (E5 Section 15.4.5.1).
55099 */
55100
55101 if (!DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
55102 goto skip_array_exotic;
55103 }
55104
55105 if (key == DUK_HTHREAD_STRING_LENGTH(thr)) {
55106 duk_harray *a;
55107
55108 /* E5 Section 15.4.5.1, step 3, steps a - i are implemented here, j - n at the end */
55109 if (!has_value) {
55110 DUK_DDD(DUK_DDDPRINT("exotic array behavior for 'length', but no value in descriptor -> normal behavior"));
55111 goto skip_array_exotic;
55112 }
55113
55114 DUK_DDD(DUK_DDDPRINT("exotic array behavior for 'length', value present in descriptor -> exotic behavior"));
55115
55116 /*
55117 * Get old and new length
55118 */
55119
55120 a = (duk_harray *) obj;
55121 DUK_ASSERT_HARRAY_VALID(a);
55122 arrlen_old_len = a->length;
55123
55124 DUK_ASSERT(idx_value >= 0);
55125 arrlen_new_len = duk__to_new_array_length_checked(thr, DUK_GET_TVAL_POSIDX(ctx, idx_value));
55126 duk_push_u32(ctx, arrlen_new_len);
55127 duk_replace(ctx, idx_value); /* step 3.e: replace 'Desc.[[Value]]' */
55128
55129 DUK_DDD(DUK_DDDPRINT("old_len=%ld, new_len=%ld", (long) arrlen_old_len, (long) arrlen_new_len));
55130
55131 if (arrlen_new_len >= arrlen_old_len) {
55132 /* standard behavior, step 3.f.i */
55133 DUK_DDD(DUK_DDDPRINT("new length is same or higher as previous => standard behavior"));
55134 goto skip_array_exotic;
55135 }
55136 DUK_DDD(DUK_DDDPRINT("new length is smaller than previous => exotic post behavior"));
55137
55138 /* XXX: consolidated algorithm step 15.f -> redundant? */
55139 if (DUK_HARRAY_LENGTH_NONWRITABLE(a) && !force_flag) {
55140 /* Array .length is always non-configurable; if it's also
55141 * non-writable, don't allow it to be written.
55142 */
55143 goto fail_not_configurable;
55144 }
55145
55146 /* steps 3.h and 3.i */
55147 if (has_writable && !is_writable) {
55148 DUK_DDD(DUK_DDDPRINT("desc writable is false, force it back to true, and flag pending write protect"));
55149 is_writable = 1;
55150 pending_write_protect = 1;
55151 }
55152
55153 /* remaining actual steps are carried out if standard DefineOwnProperty succeeds */
55154 } else if (arr_idx != DUK__NO_ARRAY_INDEX) {
55155 /* XXX: any chance of unifying this with the 'length' key handling? */
55156
55157 /* E5 Section 15.4.5.1, step 4 */
55158 duk_uint32_t old_len;
55159 duk_harray *a;
55160
55161 a = (duk_harray *) obj;
55162 DUK_ASSERT_HARRAY_VALID(a);
55163
55164 old_len = a->length;
55165
55166 if (arr_idx >= old_len) {
55167 DUK_DDD(DUK_DDDPRINT("defineProperty requires array length update "
55168 "(arr_idx=%ld, old_len=%ld)",
55169 (long) arr_idx, (long) old_len));
55170
55171 if (DUK_HARRAY_LENGTH_NONWRITABLE(a) && !force_flag) {
55172 /* Array .length is always non-configurable, so
55173 * if it's also non-writable, don't allow a value
55174 * write. With force flag allow writing.
55175 */
55176 goto fail_not_configurable;
55177 }
55178
55179 /* actual update happens once write has been completed without
55180 * error below.
55181 */
55182 DUK_ASSERT(arr_idx != 0xffffffffUL);
55183 arridx_new_array_length = arr_idx + 1;
55184 } else {
55185 DUK_DDD(DUK_DDDPRINT("defineProperty does not require length update "
55186 "(arr_idx=%ld, old_len=%ld) -> standard behavior",
55187 (long) arr_idx, (long) old_len));
55188 }
55189 }
55190 skip_array_exotic:
55191
55192 /* XXX: There is currently no support for writing buffer object
55193 * indexed elements here. Attempt to do so will succeed and
55194 * write a concrete property into the buffer object. This should
55195 * be fixed at some point but because buffers are a custom feature
55196 * anyway, this is relatively unimportant.
55197 */
55198
55199 /*
55200 * Actual Object.defineProperty() default algorithm.
55201 */
55202
55203 /*
55204 * First check whether property exists; if not, simple case. This covers
55205 * steps 1-4.
55206 */
55207
55208 if (!duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE)) {
55209 DUK_DDD(DUK_DDDPRINT("property does not exist"));
55210
55211 if (!DUK_HOBJECT_HAS_EXTENSIBLE(obj) && !force_flag) {
55212 goto fail_not_extensible;
55213 }
55214
55215#if defined(DUK_USE_ROM_OBJECTS)
55216 /* ROM objects are never extensible but force flag may
55217 * allow us to come here anyway.
55218 */
55219 DUK_ASSERT(!DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj) || !DUK_HOBJECT_HAS_EXTENSIBLE(obj));
55220 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
55221 DUK_D(DUK_DPRINT("attempt to define property on a read-only target object"));
55222 goto fail_not_configurable;
55223 }
55224#endif
55225
55226 /* XXX: share final setting code for value and flags? difficult because
55227 * refcount code is different. Share entry allocation? But can't allocate
55228 * until array index checked.
55229 */
55230
55231 /* steps 4.a and 4.b are tricky */
55232 if (has_set || has_get) {
55233 duk_int_t e_idx;
55234
55235 DUK_DDD(DUK_DDDPRINT("create new accessor property"));
55236
55237 DUK_ASSERT(has_set || set == NULL);
55238 DUK_ASSERT(has_get || get == NULL);
55239 DUK_ASSERT(!has_value);
55240 DUK_ASSERT(!has_writable);
55241
55242 new_flags = DUK_PROPDESC_FLAG_ACCESSOR; /* defaults, E5 Section 8.6.1, Table 7 */
55243 if (has_enumerable && is_enumerable) {
55244 new_flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
55245 }
55246 if (has_configurable && is_configurable) {
55247 new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
55248 }
55249
55250 if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
55251 DUK_DDD(DUK_DDDPRINT("accessor cannot go to array part, abandon array"));
55252 duk__abandon_array_checked(thr, obj);
55253 }
55254
55255 /* write to entry part */
55256 e_idx = duk__alloc_entry_checked(thr, obj, key);
55257 DUK_ASSERT(e_idx >= 0);
55258
55259 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, e_idx, get);
55260 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, e_idx, set);
55261 DUK_HOBJECT_INCREF_ALLOWNULL(thr, get);
55262 DUK_HOBJECT_INCREF_ALLOWNULL(thr, set);
55263
55264 DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, e_idx, new_flags);
55265 goto success_exotics;
55266 } else {
55267 duk_int_t e_idx;
55268 duk_tval *tv2;
55269
55270 DUK_DDD(DUK_DDDPRINT("create new data property"));
55271
55272 DUK_ASSERT(!has_set);
55273 DUK_ASSERT(!has_get);
55274
55275 new_flags = 0; /* defaults, E5 Section 8.6.1, Table 7 */
55276 if (has_writable && is_writable) {
55277 new_flags |= DUK_PROPDESC_FLAG_WRITABLE;
55278 }
55279 if (has_enumerable && is_enumerable) {
55280 new_flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
55281 }
55282 if (has_configurable && is_configurable) {
55283 new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
55284 }
55285 if (has_value) {
55286 duk_tval *tv_tmp = duk_require_tval(ctx, idx_value);
55287 DUK_TVAL_SET_TVAL(&tv, tv_tmp);
55288 } else {
55289 DUK_TVAL_SET_UNDEFINED(&tv); /* default value */
55290 }
55291
55292 if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_ARRAY_PART(obj)) {
55293 if (new_flags == DUK_PROPDESC_FLAGS_WEC) {
55294#if 0
55295 DUK_DDD(DUK_DDDPRINT("new data property attributes match array defaults, attempt to write to array part"));
55296 /* may become sparse...*/
55297#endif
55298 /* XXX: handling for array part missing now; this doesn't affect
55299 * compliance but causes array entry writes using defineProperty()
55300 * to always abandon array part.
55301 */
55302 }
55303 DUK_DDD(DUK_DDDPRINT("new data property cannot go to array part, abandon array"));
55304 duk__abandon_array_checked(thr, obj);
55305 /* fall through */
55306 }
55307
55308 /* write to entry part */
55309 e_idx = duk__alloc_entry_checked(thr, obj, key);
55310 DUK_ASSERT(e_idx >= 0);
55311 tv2 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, e_idx);
55312 DUK_TVAL_SET_TVAL(tv2, &tv);
55313 DUK_TVAL_INCREF(thr, tv2);
55314
55315 DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, e_idx, new_flags);
55316 goto success_exotics;
55317 }
55318 DUK_UNREACHABLE();
55319 }
55320
55321 /* we currently assume virtual properties are not configurable (as none of them are) */
55322 DUK_ASSERT((curr.e_idx >= 0 || curr.a_idx >= 0) || !(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE));
55323
55324 /* [obj key desc value get set curr_value] */
55325
55326 /*
55327 * Property already exists. Steps 5-6 detect whether any changes need
55328 * to be made.
55329 */
55330
55331 if (has_enumerable) {
55332 if (is_enumerable) {
55333 if (!(curr.flags & DUK_PROPDESC_FLAG_ENUMERABLE)) {
55334 goto need_check;
55335 }
55336 } else {
55337 if (curr.flags & DUK_PROPDESC_FLAG_ENUMERABLE) {
55338 goto need_check;
55339 }
55340 }
55341 }
55342 if (has_configurable) {
55343 if (is_configurable) {
55344 if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
55345 goto need_check;
55346 }
55347 } else {
55348 if (curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) {
55349 goto need_check;
55350 }
55351 }
55352 }
55353 if (has_value) {
55354 duk_tval *tmp1;
55355 duk_tval *tmp2;
55356
55357 /* attempt to change from accessor to data property */
55358 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
55359 goto need_check;
55360 }
55361
55362 tmp1 = duk_require_tval(ctx, -1); /* curr value */
55363 tmp2 = duk_require_tval(ctx, idx_value); /* new value */
55364 if (!duk_js_samevalue(tmp1, tmp2)) {
55365 goto need_check;
55366 }
55367 }
55368 if (has_writable) {
55369 /* attempt to change from accessor to data property */
55370 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
55371 goto need_check;
55372 }
55373
55374 if (is_writable) {
55375 if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE)) {
55376 goto need_check;
55377 }
55378 } else {
55379 if (curr.flags & DUK_PROPDESC_FLAG_WRITABLE) {
55380 goto need_check;
55381 }
55382 }
55383 }
55384 if (has_set) {
55385 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
55386 if (set != curr.set) {
55387 goto need_check;
55388 }
55389 } else {
55390 goto need_check;
55391 }
55392 }
55393 if (has_get) {
55394 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
55395 if (get != curr.get) {
55396 goto need_check;
55397 }
55398 } else {
55399 goto need_check;
55400 }
55401 }
55402
55403 /* property exists, either 'desc' is empty, or all values
55404 * match (SameValue)
55405 */
55406 goto success_no_exotics;
55407
55408 need_check:
55409
55410 /*
55411 * Some change(s) need to be made. Steps 7-11.
55412 */
55413
55414 /* shared checks for all descriptor types */
55415 if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
55416 if (has_configurable && is_configurable) {
55417 goto fail_not_configurable;
55418 }
55419 if (has_enumerable) {
55420 if (curr.flags & DUK_PROPDESC_FLAG_ENUMERABLE) {
55421 if (!is_enumerable) {
55422 goto fail_not_configurable;
55423 }
55424 } else {
55425 if (is_enumerable) {
55426 goto fail_not_configurable;
55427 }
55428 }
55429 }
55430 }
55431
55432 /* Virtual properties don't have backing so they can't mostly be
55433 * edited. Some virtual properties are, however, writable: for
55434 * example, virtual index properties of buffer objects and Array
55435 * instance .length. These are not configurable so the checks
55436 * above mostly cover attempts to change them, except when the
55437 * duk_def_prop() call is used with DUK_DEFPROP_FORCE; even in
55438 * that case we can't forcibly change the property attributes
55439 * because they don't have concrete backing.
55440 */
55441
55442 /* XXX: for ROM objects too it'd be best if value modify was
55443 * allowed if the value matches SameValue.
55444 */
55445 /* Reject attempt to change a read-only object. */
55446#if defined(DUK_USE_ROM_OBJECTS)
55447 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
55448 DUK_DD(DUK_DDPRINT("attempt to define property on read-only target object"));
55449 goto fail_not_configurable;
55450 }
55451#endif
55452
55453 /* descriptor type specific checks */
55454 if (has_set || has_get) {
55455 /* IsAccessorDescriptor(desc) == true */
55456 DUK_ASSERT(!has_writable);
55457 DUK_ASSERT(!has_value);
55458
55459 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
55460 /* curr and desc are accessors */
55461 if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
55462 if (has_set && set != curr.set) {
55463 goto fail_not_configurable;
55464 }
55465 if (has_get && get != curr.get) {
55466 goto fail_not_configurable;
55467 }
55468 }
55469 } else {
55470 duk_bool_t rc;
55471 duk_tval *tv1;
55472
55473 /* curr is data, desc is accessor */
55474 if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
55475 goto fail_not_configurable;
55476 }
55477
55478 DUK_DDD(DUK_DDDPRINT("convert property to accessor property"));
55479 if (curr.a_idx >= 0) {
55480 DUK_DDD(DUK_DDDPRINT("property to convert is stored in an array entry, abandon array and re-lookup"));
55481 duk__abandon_array_checked(thr, obj);
55482 duk_pop(ctx); /* remove old value */
55483 rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE);
55484 DUK_UNREF(rc);
55485 DUK_ASSERT(rc != 0);
55486 DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0);
55487 }
55488 if (curr.e_idx < 0) {
55489 DUK_ASSERT(curr.a_idx < 0 && curr.e_idx < 0);
55490 goto fail_virtual; /* safeguard for virtual property */
55491 }
55492
55493 DUK_ASSERT(curr.e_idx >= 0);
55494 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
55495
55496 tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx);
55497 DUK_TVAL_SET_UNDEFINED_UPDREF_NORZ(thr, tv1); /* XXX: just decref */
55498
55499 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, NULL);
55500 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, NULL);
55501 DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(thr->heap, obj, curr.e_idx);
55502 DUK_HOBJECT_E_SLOT_SET_ACCESSOR(thr->heap, obj, curr.e_idx);
55503
55504 DUK_DDD(DUK_DDDPRINT("flags after data->accessor conversion: 0x%02lx",
55505 (unsigned long) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, curr.e_idx)));
55506 /* Update curr.flags; faster than a re-lookup. */
55507 curr.flags &= ~DUK_PROPDESC_FLAG_WRITABLE;
55508 curr.flags |= DUK_PROPDESC_FLAG_ACCESSOR;
55509 }
55510 } else if (has_value || has_writable) {
55511 /* IsDataDescriptor(desc) == true */
55512 DUK_ASSERT(!has_set);
55513 DUK_ASSERT(!has_get);
55514
55515 if (curr.flags & DUK_PROPDESC_FLAG_ACCESSOR) {
55516 duk_hobject *tmp;
55517
55518 /* curr is accessor, desc is data */
55519 if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
55520 goto fail_not_configurable;
55521 }
55522
55523 /* curr is accessor -> cannot be in array part. */
55524 DUK_ASSERT(curr.a_idx < 0);
55525 if (curr.e_idx < 0) {
55526 goto fail_virtual; /* safeguard; no virtual accessors now */
55527 }
55528
55529 DUK_DDD(DUK_DDDPRINT("convert property to data property"));
55530
55531 DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
55532 tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, curr.e_idx);
55533 DUK_UNREF(tmp);
55534 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, NULL);
55535 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp);
55536 tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, curr.e_idx);
55537 DUK_UNREF(tmp);
55538 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, NULL);
55539 DUK_HOBJECT_DECREF_NORZ_ALLOWNULL(thr, tmp);
55540
55541 DUK_TVAL_SET_UNDEFINED(DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx));
55542 DUK_HOBJECT_E_SLOT_CLEAR_WRITABLE(thr->heap, obj, curr.e_idx);
55543 DUK_HOBJECT_E_SLOT_CLEAR_ACCESSOR(thr->heap, obj, curr.e_idx);
55544
55545 DUK_DDD(DUK_DDDPRINT("flags after accessor->data conversion: 0x%02lx",
55546 (unsigned long) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, curr.e_idx)));
55547
55548 /* Update curr.flags; faster than a re-lookup. */
55549 curr.flags &= ~(DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_ACCESSOR);
55550 } else {
55551 /* curr and desc are data */
55552 if (!(curr.flags & DUK_PROPDESC_FLAG_CONFIGURABLE) && !force_flag) {
55553 if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE) && has_writable && is_writable) {
55554 goto fail_not_configurable;
55555 }
55556 /* Note: changing from writable to non-writable is OK */
55557 if (!(curr.flags & DUK_PROPDESC_FLAG_WRITABLE) && has_value) {
55558 duk_tval *tmp1 = duk_require_tval(ctx, -1); /* curr value */
55559 duk_tval *tmp2 = duk_require_tval(ctx, idx_value); /* new value */
55560 if (!duk_js_samevalue(tmp1, tmp2)) {
55561 goto fail_not_configurable;
55562 }
55563 }
55564 }
55565 }
55566 } else {
55567 /* IsGenericDescriptor(desc) == true; this means in practice that 'desc'
55568 * only has [[Enumerable]] or [[Configurable]] flag updates, which are
55569 * allowed at this point.
55570 */
55571
55572 DUK_ASSERT(!has_value && !has_writable && !has_get && !has_set);
55573 }
55574
55575 /*
55576 * Start doing property attributes updates. Steps 12-13.
55577 *
55578 * Start by computing new attribute flags without writing yet.
55579 * Property type conversion is done above if necessary.
55580 */
55581
55582 new_flags = curr.flags;
55583
55584 if (has_enumerable) {
55585 if (is_enumerable) {
55586 new_flags |= DUK_PROPDESC_FLAG_ENUMERABLE;
55587 } else {
55588 new_flags &= ~DUK_PROPDESC_FLAG_ENUMERABLE;
55589 }
55590 }
55591 if (has_configurable) {
55592 if (is_configurable) {
55593 new_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
55594 } else {
55595 new_flags &= ~DUK_PROPDESC_FLAG_CONFIGURABLE;
55596 }
55597 }
55598 if (has_writable) {
55599 if (is_writable) {
55600 new_flags |= DUK_PROPDESC_FLAG_WRITABLE;
55601 } else {
55602 new_flags &= ~DUK_PROPDESC_FLAG_WRITABLE;
55603 }
55604 }
55605
55606 /* XXX: write protect after flag? -> any chance of handling it here? */
55607
55608 DUK_DDD(DUK_DDDPRINT("new flags that we want to write: 0x%02lx",
55609 (unsigned long) new_flags));
55610
55611 /*
55612 * Check whether we need to abandon an array part (if it exists)
55613 */
55614
55615 if (curr.a_idx >= 0) {
55616 duk_bool_t rc;
55617
55618 DUK_ASSERT(curr.e_idx < 0);
55619
55620 if (new_flags == DUK_PROPDESC_FLAGS_WEC) {
55621 duk_tval *tv1, *tv2;
55622
55623 DUK_DDD(DUK_DDDPRINT("array index, new property attributes match array defaults, update in-place"));
55624
55625 DUK_ASSERT(curr.flags == DUK_PROPDESC_FLAGS_WEC); /* must have been, since in array part */
55626 DUK_ASSERT(!has_set);
55627 DUK_ASSERT(!has_get);
55628 DUK_ASSERT(idx_value >= 0); /* must be: if attributes match and we get here the value must differ (otherwise no change) */
55629
55630 tv2 = duk_require_tval(ctx, idx_value);
55631 tv1 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, curr.a_idx);
55632 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects; may invalidate a_idx */
55633 goto success_exotics;
55634 }
55635
55636 DUK_DDD(DUK_DDDPRINT("array index, new property attributes do not match array defaults, abandon array and re-lookup"));
55637 duk__abandon_array_checked(thr, obj);
55638 duk_pop(ctx); /* remove old value */
55639 rc = duk__get_own_propdesc_raw(thr, obj, key, arr_idx, &curr, DUK_GETDESC_FLAG_PUSH_VALUE);
55640 DUK_UNREF(rc);
55641 DUK_ASSERT(rc != 0);
55642 DUK_ASSERT(curr.e_idx >= 0 && curr.a_idx < 0);
55643 }
55644
55645 DUK_DDD(DUK_DDDPRINT("updating existing property in entry part"));
55646
55647 /* Array case is handled comprehensively above: either in entry
55648 * part or a virtual property.
55649 */
55650 DUK_ASSERT(curr.a_idx < 0);
55651
55652 DUK_DDD(DUK_DDDPRINT("update existing property attributes"));
55653 if (curr.e_idx >= 0) {
55654 DUK_HOBJECT_E_SET_FLAGS(thr->heap, obj, curr.e_idx, new_flags);
55655 } else {
55656 /* For Array .length the only allowed transition is for .length
55657 * to become non-writable.
55658 */
55659 if (key == DUK_HTHREAD_STRING_LENGTH(thr) && DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
55660 duk_harray *a;
55661 a = (duk_harray *) obj;
55662 DUK_DD(DUK_DDPRINT("Object.defineProperty() attribute update for duk_harray .length -> %02lx", (unsigned long) new_flags));
55663 DUK_ASSERT_HARRAY_VALID(a);
55664 if ((new_flags & DUK_PROPDESC_FLAGS_EC) != (curr.flags & DUK_PROPDESC_FLAGS_EC)) {
55665 DUK_D(DUK_DPRINT("Object.defineProperty() attempt to change virtual array .length enumerable or configurable attribute, fail"));
55666 goto fail_virtual;
55667 }
55668 if (new_flags & DUK_PROPDESC_FLAG_WRITABLE) {
55669 DUK_HARRAY_SET_LENGTH_WRITABLE(a);
55670 } else {
55671 DUK_HARRAY_SET_LENGTH_NONWRITABLE(a);
55672 }
55673 }
55674 }
55675
55676 if (has_set) {
55677 duk_hobject *tmp;
55678
55679 /* Virtual properties are non-configurable but with a 'force'
55680 * flag we might come here so check explicitly for virtual.
55681 */
55682 if (curr.e_idx < 0) {
55683 goto fail_virtual;
55684 }
55685
55686 DUK_DDD(DUK_DDDPRINT("update existing property setter"));
55687 DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
55688
55689 tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, obj, curr.e_idx);
55690 DUK_UNREF(tmp);
55691 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, obj, curr.e_idx, set);
55692 DUK_HOBJECT_INCREF_ALLOWNULL(thr, set);
55693 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); /* side effects; may invalidate e_idx */
55694 }
55695 if (has_get) {
55696 duk_hobject *tmp;
55697
55698 if (curr.e_idx < 0) {
55699 goto fail_virtual;
55700 }
55701
55702 DUK_DDD(DUK_DDDPRINT("update existing property getter"));
55703 DUK_ASSERT(DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
55704
55705 tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, obj, curr.e_idx);
55706 DUK_UNREF(tmp);
55707 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, obj, curr.e_idx, get);
55708 DUK_HOBJECT_INCREF_ALLOWNULL(thr, get);
55709 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); /* side effects; may invalidate e_idx */
55710 }
55711 if (has_value) {
55712 duk_tval *tv1, *tv2;
55713
55714 DUK_DDD(DUK_DDDPRINT("update existing property value"));
55715
55716 if (curr.e_idx >= 0) {
55717 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, obj, curr.e_idx));
55718 tv2 = duk_require_tval(ctx, idx_value);
55719 tv1 = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, obj, curr.e_idx);
55720 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects; may invalidate e_idx */
55721 } else {
55722 DUK_ASSERT(curr.a_idx < 0); /* array part case handled comprehensively previously */
55723
55724 DUK_DD(DUK_DDPRINT("Object.defineProperty(), value update for virtual property"));
55725 /* XXX: Uint8Array and other typed array virtual writes not currently
55726 * handled.
55727 */
55728 if (key == DUK_HTHREAD_STRING_LENGTH(thr) && DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
55729 duk_harray *a;
55730 a = (duk_harray *) obj;
55731 DUK_DD(DUK_DDPRINT("Object.defineProperty() value update for duk_harray .length -> %ld", (long) arrlen_new_len));
55732 DUK_ASSERT_HARRAY_VALID(a);
55733 a->length = arrlen_new_len;
55734 } else {
55735 goto fail_virtual; /* should not happen */
55736 }
55737 }
55738 }
55739
55740 /*
55741 * Standard algorithm succeeded without errors, check for exotic post-behaviors.
55742 *
55743 * Arguments exotic behavior in E5 Section 10.6 occurs after the standard
55744 * [[DefineOwnProperty]] has completed successfully.
55745 *
55746 * Array exotic behavior in E5 Section 15.4.5.1 is implemented partly
55747 * prior to the default [[DefineOwnProperty]], but:
55748 * - for an array index key (e.g. "10") the final 'length' update occurs here
55749 * - for 'length' key the element deletion and 'length' update occurs here
55750 */
55751
55752 success_exotics:
55753
55754 /* curr.a_idx or curr.e_idx may have been invalidated by side effects
55755 * above.
55756 */
55757
55758 /* [obj key desc value get set curr_value] */
55759
55760 if (DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)) {
55761 duk_harray *a;
55762
55763 a = (duk_harray *) obj;
55764 DUK_ASSERT_HARRAY_VALID(a);
55765
55766 if (arridx_new_array_length > 0) {
55767 /*
55768 * Note: zero works as a "no update" marker because the new length
55769 * can never be zero after a new property is written.
55770 */
55771
55772 /* E5 Section 15.4.5.1, steps 4.e.i - 4.e.ii */
55773
55774 DUK_DDD(DUK_DDDPRINT("defineProperty successful, pending array length update to: %ld",
55775 (long) arridx_new_array_length));
55776
55777 a->length = arridx_new_array_length;
55778 }
55779
55780 if (key == DUK_HTHREAD_STRING_LENGTH(thr) && arrlen_new_len < arrlen_old_len) {
55781 /*
55782 * E5 Section 15.4.5.1, steps 3.k - 3.n. The order at the end combines
55783 * the error case 3.l.iii and the success case 3.m-3.n.
55784 */
55785
55786 /* XXX: investigate whether write protect can be handled above, if we
55787 * just update length here while ignoring its protected status
55788 */
55789
55790 duk_uint32_t result_len;
55791 duk_bool_t rc;
55792
55793 DUK_DDD(DUK_DDDPRINT("defineProperty successful, key is 'length', exotic array behavior, "
55794 "doing array element deletion and length update"));
55795
55796 rc = duk__handle_put_array_length_smaller(thr, obj, arrlen_old_len, arrlen_new_len, force_flag, &result_len);
55797
55798 /* update length (curr points to length, and we assume it's still valid) */
55799 DUK_ASSERT(result_len >= arrlen_new_len && result_len <= arrlen_old_len);
55800
55801 a->length = result_len;
55802
55803 if (pending_write_protect) {
55804 DUK_DDD(DUK_DDDPRINT("setting array length non-writable (pending writability update)"));
55805 DUK_HARRAY_SET_LENGTH_NONWRITABLE(a);
55806 }
55807
55808 /* XXX: shrink array allocation or entries compaction here? */
55809 if (!rc) {
55810 DUK_DD(DUK_DDPRINT("array length write only partially successful"));
55811 goto fail_not_configurable;
55812 }
55813 }
55814 } else if (arr_idx != DUK__NO_ARRAY_INDEX && DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(obj)) {
55815 duk_hobject *map;
55816 duk_hobject *varenv;
55817
55818 DUK_ASSERT(arridx_new_array_length == 0);
55819 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(obj)); /* traits are separate; in particular, arguments not an array */
55820
55821 map = NULL;
55822 varenv = NULL;
55823 if (!duk__lookup_arguments_map(thr, obj, key, &curr, &map, &varenv)) {
55824 goto success_no_exotics;
55825 }
55826 DUK_ASSERT(map != NULL);
55827 DUK_ASSERT(varenv != NULL);
55828
55829 /* [obj key desc value get set curr_value varname] */
55830
55831 if (has_set || has_get) {
55832 /* = IsAccessorDescriptor(Desc) */
55833 DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map' "
55834 "changed to an accessor, delete arguments binding"));
55835
55836 (void) duk_hobject_delprop_raw(thr, map, key, 0); /* ignore result */
55837 } else {
55838 /* Note: this order matters (final value before deleting map entry must be done) */
55839 DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', "
55840 "check for value update / binding deletion"));
55841
55842 if (has_value) {
55843 duk_hstring *varname;
55844
55845 DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', "
55846 "update bound value (variable/argument)"));
55847
55848 varname = duk_require_hstring(ctx, -1);
55849 DUK_ASSERT(varname != NULL);
55850
55851 DUK_DDD(DUK_DDDPRINT("arguments object automatic putvar for a bound variable; "
55852 "key=%!O, varname=%!O, value=%!T",
55853 (duk_heaphdr *) key,
55854 (duk_heaphdr *) varname,
55855 (duk_tval *) duk_require_tval(ctx, idx_value)));
55856
55857 /* strict flag for putvar comes from our caller (currently: fixed) */
55858 duk_js_putvar_envrec(thr, varenv, varname, duk_require_tval(ctx, idx_value), 1 /*throw_flag*/);
55859 }
55860 if (has_writable && !is_writable) {
55861 DUK_DDD(DUK_DDDPRINT("defineProperty successful, key mapped to arguments 'map', "
55862 "changed to non-writable, delete arguments binding"));
55863
55864 (void) duk_hobject_delprop_raw(thr, map, key, 0); /* ignore result */
55865 }
55866 }
55867
55868 /* 'varname' is in stack in this else branch, leaving an unbalanced stack below,
55869 * but this doesn't matter now.
55870 */
55871 }
55872
55873 success_no_exotics:
55874 /* Some code paths use NORZ macros for simplicity, ensure refzero
55875 * handling is completed.
55876 */
55877 DUK_REFZERO_CHECK_SLOW(thr);
55878 return 1;
55879
55880 fail_not_extensible:
55881 if (throw_flag) {
55882 DUK_ERROR_TYPE(thr, DUK_STR_NOT_EXTENSIBLE);
55883 }
55884 return 0;
55885
55886 fail_virtual: /* just use the same "not configurable" error message" */
55887 fail_not_configurable:
55888 if (throw_flag) {
55889 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
55890 }
55891 return 0;
55892}
55893
55894/*
55895 * Object.prototype.hasOwnProperty() and Object.prototype.propertyIsEnumerable().
55896 */
55897
55898DUK_INTERNAL duk_bool_t duk_hobject_object_ownprop_helper(duk_context *ctx, duk_small_uint_t required_desc_flags) {
55899 duk_hthread *thr = (duk_hthread *) ctx;
55900 duk_hstring *h_v;
55901 duk_hobject *h_obj;
55902 duk_propdesc desc;
55903 duk_bool_t ret;
55904
55905 /* coercion order matters */
55906 h_v = duk_to_hstring_acceptsymbol(ctx, 0);
55907 DUK_ASSERT(h_v != NULL);
55908
55909 h_obj = duk_push_this_coercible_to_object(ctx);
55910 DUK_ASSERT(h_obj != NULL);
55911
55912 ret = duk_hobject_get_own_propdesc(thr, h_obj, h_v, &desc, 0 /*flags*/); /* don't push value */
55913
55914 duk_push_boolean(ctx, ret && ((desc.flags & required_desc_flags) == required_desc_flags));
55915 return 1;
55916}
55917
55918/*
55919 * Object.seal() and Object.freeze() (E5 Sections 15.2.3.8 and 15.2.3.9)
55920 *
55921 * Since the algorithms are similar, a helper provides both functions.
55922 * Freezing is essentially sealing + making plain properties non-writable.
55923 *
55924 * Note: virtual (non-concrete) properties which are non-configurable but
55925 * writable would pose some problems, but such properties do not currently
55926 * exist (all virtual properties are non-configurable and non-writable).
55927 * If they did exist, the non-configurability does NOT prevent them from
55928 * becoming non-writable. However, this change should be recorded somehow
55929 * so that it would turn up (e.g. when getting the property descriptor),
55930 * requiring some additional flags in the object.
55931 */
55932
55933DUK_INTERNAL void duk_hobject_object_seal_freeze_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_freeze) {
55934 duk_uint_fast32_t i;
55935
55936 DUK_ASSERT(thr != NULL);
55937 DUK_ASSERT(thr->heap != NULL);
55938 DUK_ASSERT(obj != NULL);
55939
55940 DUK_ASSERT_VALSTACK_SPACE(thr, DUK__VALSTACK_SPACE);
55941
55942#if defined(DUK_USE_ROM_OBJECTS)
55943 if (DUK_HEAPHDR_HAS_READONLY((duk_heaphdr *) obj)) {
55944 DUK_DD(DUK_DDPRINT("attempt to seal/freeze a readonly object, reject"));
55945 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CONFIGURABLE);
55946 }
55947#endif
55948
55949 /*
55950 * Abandon array part because all properties must become non-configurable.
55951 * Note that this is now done regardless of whether this is always the case
55952 * (skips check, but performance problem if caller would do this many times
55953 * for the same object; not likely).
55954 */
55955
55956 duk__abandon_array_checked(thr, obj);
55957 DUK_ASSERT(DUK_HOBJECT_GET_ASIZE(obj) == 0);
55958
55959 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
55960 duk_uint8_t *fp;
55961
55962 /* since duk__abandon_array_checked() causes a resize, there should be no gaps in keys */
55963 DUK_ASSERT(DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i) != NULL);
55964
55965 /* avoid multiple computations of flags address; bypasses macros */
55966 fp = DUK_HOBJECT_E_GET_FLAGS_PTR(thr->heap, obj, i);
55967 if (is_freeze && !((*fp) & DUK_PROPDESC_FLAG_ACCESSOR)) {
55968 *fp &= ~(DUK_PROPDESC_FLAG_WRITABLE | DUK_PROPDESC_FLAG_CONFIGURABLE);
55969 } else {
55970 *fp &= ~DUK_PROPDESC_FLAG_CONFIGURABLE;
55971 }
55972 }
55973
55974 DUK_HOBJECT_CLEAR_EXTENSIBLE(obj);
55975
55976 /* no need to compact since we already did that in duk__abandon_array_checked()
55977 * (regardless of whether an array part existed or not.
55978 */
55979
55980 return;
55981}
55982
55983/*
55984 * Object.isSealed() and Object.isFrozen() (E5 Sections 15.2.3.11, 15.2.3.13)
55985 *
55986 * Since the algorithms are similar, a helper provides both functions.
55987 * Freezing is essentially sealing + making plain properties non-writable.
55988 *
55989 * Note: all virtual (non-concrete) properties are currently non-configurable
55990 * and non-writable (and there are no accessor virtual properties), so they don't
55991 * need to be considered here now.
55992 */
55993
55994DUK_INTERNAL duk_bool_t duk_hobject_object_is_sealed_frozen_helper(duk_hthread *thr, duk_hobject *obj, duk_bool_t is_frozen) {
55995 duk_uint_fast32_t i;
55996
55997 DUK_ASSERT(obj != NULL);
55998 DUK_UNREF(thr);
55999
56000 /* Note: no allocation pressure, no need to check refcounts etc */
56001
56002 /* must not be extensible */
56003 if (DUK_HOBJECT_HAS_EXTENSIBLE(obj)) {
56004 return 0;
56005 }
56006
56007 /* all virtual properties are non-configurable and non-writable */
56008
56009 /* entry part must not contain any configurable properties, or
56010 * writable properties (if is_frozen).
56011 */
56012 for (i = 0; i < DUK_HOBJECT_GET_ENEXT(obj); i++) {
56013 duk_small_uint_t flags;
56014
56015 if (!DUK_HOBJECT_E_GET_KEY(thr->heap, obj, i)) {
56016 continue;
56017 }
56018
56019 /* avoid multiple computations of flags address; bypasses macros */
56020 flags = (duk_small_uint_t) DUK_HOBJECT_E_GET_FLAGS(thr->heap, obj, i);
56021
56022 if (flags & DUK_PROPDESC_FLAG_CONFIGURABLE) {
56023 return 0;
56024 }
56025 if (is_frozen &&
56026 !(flags & DUK_PROPDESC_FLAG_ACCESSOR) &&
56027 (flags & DUK_PROPDESC_FLAG_WRITABLE)) {
56028 return 0;
56029 }
56030 }
56031
56032 /* array part must not contain any non-unused properties, as they would
56033 * be configurable and writable.
56034 */
56035 for (i = 0; i < DUK_HOBJECT_GET_ASIZE(obj); i++) {
56036 duk_tval *tv = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, obj, i);
56037 if (!DUK_TVAL_IS_UNUSED(tv)) {
56038 return 0;
56039 }
56040 }
56041
56042 return 1;
56043}
56044
56045/*
56046 * Object.preventExtensions() and Object.isExtensible() (E5 Sections 15.2.3.10, 15.2.3.13)
56047 *
56048 * Not needed, implemented by macros DUK_HOBJECT_{HAS,CLEAR,SET}_EXTENSIBLE
56049 * and the Object built-in bindings.
56050 */
56051
56052/* automatic undefs */
56053#undef DUK__HASH_DELETED
56054#undef DUK__HASH_INITIAL
56055#undef DUK__HASH_PROBE_STEP
56056#undef DUK__HASH_UNUSED
56057#undef DUK__NO_ARRAY_INDEX
56058#undef DUK__VALSTACK_PROXY_LOOKUP
56059#undef DUK__VALSTACK_SPACE
56060/*
56061 * Misc support functions
56062 */
56063
56064/* #include duk_internal.h -> already included */
56065
56066DUK_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) {
56067 duk_uint32_t boff;
56068 const duk_uint8_t *p, *p_start, *p_end;
56069 duk_ucodepoint_t cp1;
56070 duk_ucodepoint_t cp2;
56071
56072 /* Caller must check character offset to be inside the string. */
56073 DUK_ASSERT(thr != NULL);
56074 DUK_ASSERT(h != NULL);
56075 DUK_ASSERT_DISABLE(pos >= 0); /* unsigned */
56076 DUK_ASSERT(pos < (duk_uint_t) DUK_HSTRING_GET_CHARLEN(h));
56077
56078 boff = duk_heap_strcache_offset_char2byte(thr, h, (duk_uint32_t) pos);
56079 DUK_DDD(DUK_DDDPRINT("charCodeAt: pos=%ld -> boff=%ld, str=%!O",
56080 (long) pos, (long) boff, (duk_heaphdr *) h));
56081 DUK_ASSERT_DISABLE(boff >= 0);
56082 DUK_ASSERT(boff < DUK_HSTRING_GET_BYTELEN(h));
56083
56084 p_start = DUK_HSTRING_GET_DATA(h);
56085 p_end = p_start + DUK_HSTRING_GET_BYTELEN(h);
56086 p = p_start + boff;
56087 DUK_DDD(DUK_DDDPRINT("p_start=%p, p_end=%p, p=%p",
56088 (const void *) p_start, (const void *) p_end,
56089 (const void *) p));
56090
56091 /* For invalid UTF-8 (never happens for standard Ecmascript strings)
56092 * return U+FFFD replacement character.
56093 */
56094 if (duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp1)) {
56095 if (surrogate_aware && cp1 >= 0xd800UL && cp1 <= 0xdbffUL) {
56096 /* The decode helper is memory safe even if 'cp1' was
56097 * decoded at the end of the string and 'p' is no longer
56098 * within string memory range.
56099 */
56100 cp2 = 0; /* If call fails, this is left untouched and won't match cp2 check. */
56101 (void) duk_unicode_decode_xutf8(thr, &p, p_start, p_end, &cp2);
56102 if (cp2 >= 0xdc00UL && cp2 <= 0xdfffUL) {
56103 cp1 = ((cp1 - 0xd800UL) << 10) + (cp2 - 0xdc00UL) + 0x10000UL;
56104 }
56105 }
56106 } else {
56107 cp1 = DUK_UNICODE_CP_REPLACEMENT_CHARACTER;
56108 }
56109
56110 return cp1;
56111}
56112
56113#if !defined(DUK_USE_HSTRING_CLEN)
56114DUK_INTERNAL duk_size_t duk_hstring_get_charlen(duk_hstring *h) {
56115 if (DUK_HSTRING_HAS_ASCII(h)) {
56116 /* Most practical strings will go here. */
56117 return DUK_HSTRING_GET_BYTELEN(h);
56118 } else {
56119 return duk_unicode_unvalidated_utf8_length(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h));
56120 }
56121}
56122#endif /* !DUK_USE_HSTRING_CLEN */
56123/*
56124 * duk_hthread allocation and freeing.
56125 */
56126
56127/* #include duk_internal.h -> already included */
56128
56129/*
56130 * Allocate initial stacks for a thread. Note that 'thr' must be reachable
56131 * as a garbage collection may be triggered by the allocation attempts.
56132 * Returns zero (without leaking memory) if init fails.
56133 */
56134
56135DUK_INTERNAL duk_bool_t duk_hthread_init_stacks(duk_heap *heap, duk_hthread *thr) {
56136 duk_size_t alloc_size;
56137 duk_size_t i;
56138
56139 DUK_ASSERT(heap != NULL);
56140 DUK_ASSERT(thr != NULL);
56141 DUK_ASSERT(thr->valstack == NULL);
56142 DUK_ASSERT(thr->valstack_end == NULL);
56143 DUK_ASSERT(thr->valstack_bottom == NULL);
56144 DUK_ASSERT(thr->valstack_top == NULL);
56145 DUK_ASSERT(thr->callstack == NULL);
56146 DUK_ASSERT(thr->catchstack == NULL);
56147
56148 /* valstack */
56149 alloc_size = sizeof(duk_tval) * DUK_VALSTACK_INITIAL_SIZE;
56150 thr->valstack = (duk_tval *) DUK_ALLOC(heap, alloc_size);
56151 if (!thr->valstack) {
56152 goto fail;
56153 }
56154 DUK_MEMZERO(thr->valstack, alloc_size);
56155 thr->valstack_end = thr->valstack + DUK_VALSTACK_INITIAL_SIZE;
56156#if !defined(DUK_USE_PREFER_SIZE)
56157 thr->valstack_size = DUK_VALSTACK_INITIAL_SIZE;
56158#endif
56159 thr->valstack_bottom = thr->valstack;
56160 thr->valstack_top = thr->valstack;
56161
56162 for (i = 0; i < DUK_VALSTACK_INITIAL_SIZE; i++) {
56163 DUK_TVAL_SET_UNDEFINED(&thr->valstack[i]);
56164 }
56165
56166 /* callstack */
56167 alloc_size = sizeof(duk_activation) * DUK_CALLSTACK_INITIAL_SIZE;
56168 thr->callstack = (duk_activation *) DUK_ALLOC(heap, alloc_size);
56169 if (!thr->callstack) {
56170 goto fail;
56171 }
56172 DUK_MEMZERO(thr->callstack, alloc_size);
56173 thr->callstack_size = DUK_CALLSTACK_INITIAL_SIZE;
56174 DUK_ASSERT(thr->callstack_top == 0);
56175
56176 /* catchstack */
56177 alloc_size = sizeof(duk_catcher) * DUK_CATCHSTACK_INITIAL_SIZE;
56178 thr->catchstack = (duk_catcher *) DUK_ALLOC(heap, alloc_size);
56179 if (!thr->catchstack) {
56180 goto fail;
56181 }
56182 DUK_MEMZERO(thr->catchstack, alloc_size);
56183 thr->catchstack_size = DUK_CATCHSTACK_INITIAL_SIZE;
56184 DUK_ASSERT(thr->catchstack_top == 0);
56185
56186 return 1;
56187
56188 fail:
56189 DUK_FREE(heap, thr->valstack);
56190 DUK_FREE(heap, thr->callstack);
56191 DUK_FREE(heap, thr->catchstack);
56192
56193 thr->valstack = NULL;
56194 thr->callstack = NULL;
56195 thr->catchstack = NULL;
56196 return 0;
56197}
56198
56199/* For indirect allocs. */
56200
56201DUK_INTERNAL void *duk_hthread_get_valstack_ptr(duk_heap *heap, void *ud) {
56202 duk_hthread *thr = (duk_hthread *) ud;
56203 DUK_UNREF(heap);
56204 return (void *) thr->valstack;
56205}
56206
56207DUK_INTERNAL void *duk_hthread_get_callstack_ptr(duk_heap *heap, void *ud) {
56208 duk_hthread *thr = (duk_hthread *) ud;
56209 DUK_UNREF(heap);
56210 return (void *) thr->callstack;
56211}
56212
56213DUK_INTERNAL void *duk_hthread_get_catchstack_ptr(duk_heap *heap, void *ud) {
56214 duk_hthread *thr = (duk_hthread *) ud;
56215 DUK_UNREF(heap);
56216 return (void *) thr->catchstack;
56217}
56218/*
56219 * Initialize built-in objects. Current thread must have a valstack
56220 * and initialization errors may longjmp, so a setjmp() catch point
56221 * must exist.
56222 */
56223
56224/* #include duk_internal.h -> already included */
56225
56226/*
56227 * Encoding constants, must match genbuiltins.py
56228 */
56229
56230#define DUK__PROP_FLAGS_BITS 3
56231#define DUK__LENGTH_PROP_BITS 3
56232#define DUK__NARGS_BITS 3
56233#define DUK__PROP_TYPE_BITS 3
56234
56235#define DUK__NARGS_VARARGS_MARKER 0x07
56236
56237#define DUK__PROP_TYPE_DOUBLE 0
56238#define DUK__PROP_TYPE_STRING 1
56239#define DUK__PROP_TYPE_STRIDX 2
56240#define DUK__PROP_TYPE_BUILTIN 3
56241#define DUK__PROP_TYPE_UNDEFINED 4
56242#define DUK__PROP_TYPE_BOOLEAN_TRUE 5
56243#define DUK__PROP_TYPE_BOOLEAN_FALSE 6
56244#define DUK__PROP_TYPE_ACCESSOR 7
56245
56246/*
56247 * Create built-in objects by parsing an init bitstream generated
56248 * by genbuiltins.py.
56249 */
56250
56251#if defined(DUK_USE_ROM_OBJECTS)
56252#if defined(DUK_USE_ROM_GLOBAL_CLONE) || defined(DUK_USE_ROM_GLOBAL_INHERIT)
56253DUK_LOCAL void duk__duplicate_ram_global_object(duk_hthread *thr) {
56254 duk_context *ctx;
56255 duk_hobject *h1;
56256#if defined(DUK_USE_ROM_GLOBAL_CLONE)
56257 duk_hobject *h2;
56258 duk_uint8_t *props;
56259 duk_size_t alloc_size;
56260#endif
56261
56262 ctx = (duk_context *) thr;
56263
56264 /* XXX: refactor into internal helper, duk_clone_hobject() */
56265
56266#if defined(DUK_USE_ROM_GLOBAL_INHERIT)
56267 /* Inherit from ROM-based global object: less RAM usage, less transparent. */
56268 h1 = duk_push_object_helper(ctx,
56269 DUK_HOBJECT_FLAG_EXTENSIBLE |
56270 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL),
56271 DUK_BIDX_GLOBAL);
56272 DUK_ASSERT(h1 != NULL);
56273#elif defined(DUK_USE_ROM_GLOBAL_CLONE)
56274 /* Clone the properties of the ROM-based global object to create a
56275 * fully RAM-based global object. Uses more memory than the inherit
56276 * model but more compliant.
56277 */
56278 h1 = duk_push_object_helper(ctx,
56279 DUK_HOBJECT_FLAG_EXTENSIBLE |
56280 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_GLOBAL),
56281 DUK_BIDX_OBJECT_PROTOTYPE);
56282 DUK_ASSERT(h1 != NULL);
56283 h2 = thr->builtins[DUK_BIDX_GLOBAL];
56284 DUK_ASSERT(h2 != NULL);
56285
56286 /* Copy the property table verbatim; this handles attributes etc.
56287 * For ROM objects it's not necessary (or possible) to update
56288 * refcounts so leave them as is.
56289 */
56290 alloc_size = DUK_HOBJECT_P_ALLOC_SIZE(h2);
56291 DUK_ASSERT(alloc_size > 0);
56292 props = DUK_ALLOC(thr->heap, alloc_size);
56293 if (!props) {
56294 DUK_ERROR_ALLOC_FAILED(thr);
56295 return;
56296 }
56297 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h2) != NULL);
56298 DUK_MEMCPY((void *) props, (const void *) DUK_HOBJECT_GET_PROPS(thr->heap, h2), alloc_size);
56299
56300 /* XXX: keep property attributes or tweak them here?
56301 * Properties will now be non-configurable even when they're
56302 * normally configurable for the global object.
56303 */
56304
56305 DUK_ASSERT(DUK_HOBJECT_GET_PROPS(thr->heap, h1) == NULL);
56306 DUK_HOBJECT_SET_PROPS(thr->heap, h1, props);
56307 DUK_HOBJECT_SET_ESIZE(h1, DUK_HOBJECT_GET_ESIZE(h2));
56308 DUK_HOBJECT_SET_ENEXT(h1, DUK_HOBJECT_GET_ENEXT(h2));
56309 DUK_HOBJECT_SET_ASIZE(h1, DUK_HOBJECT_GET_ASIZE(h2));
56310 DUK_HOBJECT_SET_HSIZE(h1, DUK_HOBJECT_GET_HSIZE(h2));
56311#else
56312#error internal error in defines
56313#endif
56314
56315 duk_hobject_compact_props(thr, h1);
56316 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL] != NULL);
56317 DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL])); /* no need to decref */
56318 thr->builtins[DUK_BIDX_GLOBAL] = h1;
56319 DUK_HOBJECT_INCREF(thr, h1);
56320 DUK_D(DUK_DPRINT("duplicated global object: %!O", h1));
56321
56322
56323 /* Create a fresh object environment for the global scope. This is
56324 * needed so that the global scope points to the newly created RAM-based
56325 * global object.
56326 */
56327 h1 = duk_push_object_helper(ctx,
56328 DUK_HOBJECT_FLAG_EXTENSIBLE |
56329 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV),
56330 -1); /* no prototype */
56331 DUK_ASSERT(h1 != NULL);
56332 duk_dup_m2(ctx);
56333 duk_dup_top(ctx); /* -> [ ... new_global new_globalenv new_global new_global ] */
56334 duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
56335 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); /* always provideThis=true */
56336
56337 duk_hobject_compact_props(thr, h1);
56338 DUK_ASSERT(thr->builtins[DUK_BIDX_GLOBAL_ENV] != NULL);
56339 DUK_ASSERT(!DUK_HEAPHDR_NEEDS_REFCOUNT_UPDATE((duk_heaphdr *) thr->builtins[DUK_BIDX_GLOBAL_ENV])); /* no need to decref */
56340 thr->builtins[DUK_BIDX_GLOBAL_ENV] = h1;
56341 DUK_HOBJECT_INCREF(thr, h1);
56342 DUK_D(DUK_DPRINT("duplicated global env: %!O", h1));
56343
56344 duk_pop_2(ctx);
56345}
56346#endif /* DUK_USE_ROM_GLOBAL_CLONE || DUK_USE_ROM_GLOBAL_INHERIT */
56347
56348DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
56349 /* Setup builtins from ROM objects. All heaps/threads will share
56350 * the same readonly objects.
56351 */
56352 duk_small_uint_t i;
56353
56354 for (i = 0; i < DUK_NUM_BUILTINS; i++) {
56355 duk_hobject *h;
56356 h = (duk_hobject *) DUK_LOSE_CONST(duk_rom_builtins_bidx[i]);
56357 DUK_ASSERT(h != NULL);
56358 thr->builtins[i] = h;
56359 }
56360
56361#if defined(DUK_USE_ROM_GLOBAL_CLONE) || defined(DUK_USE_ROM_GLOBAL_INHERIT)
56362 /* By default the global object is read-only which is often much
56363 * more of an issue than having read-only built-in objects (like
56364 * RegExp, Date, etc). Use a RAM-based copy of the global object
56365 * and the global environment object for convenience.
56366 */
56367 duk__duplicate_ram_global_object(thr);
56368#endif
56369}
56370#else /* DUK_USE_ROM_OBJECTS */
56371DUK_LOCAL void duk__push_stridx(duk_context *ctx, duk_bitdecoder_ctx *bd) {
56372 duk_small_uint_t n;
56373
56374 n = (duk_small_uint_t) duk_bd_decode_varuint(bd);
56375 DUK_ASSERT_DISABLE(n >= 0); /* unsigned */
56376 DUK_ASSERT(n < DUK_HEAP_NUM_STRINGS);
56377 duk_push_hstring_stridx(ctx, n);
56378}
56379DUK_LOCAL void duk__push_string(duk_context *ctx, duk_bitdecoder_ctx *bd) {
56380 /* XXX: built-ins data could provide a maximum length that is
56381 * actually needed; bitpacked max length is now 256 bytes.
56382 */
56383 duk_uint8_t tmp[DUK_BD_BITPACKED_STRING_MAXLEN];
56384 duk_small_uint_t len;
56385
56386 len = duk_bd_decode_bitpacked_string(bd, tmp);
56387 duk_push_lstring(ctx, (const char *) tmp, (duk_size_t) len);
56388}
56389DUK_LOCAL void duk__push_stridx_or_string(duk_context *ctx, duk_bitdecoder_ctx *bd) {
56390 duk_small_uint_t n;
56391
56392 n = (duk_small_uint_t) duk_bd_decode_varuint(bd);
56393 if (n == 0) {
56394 duk__push_string(ctx, bd);
56395 } else {
56396 n--;
56397 DUK_ASSERT(n < DUK_HEAP_NUM_STRINGS);
56398 duk_push_hstring_stridx(ctx, n);
56399 }
56400}
56401DUK_LOCAL void duk__push_double(duk_context *ctx, duk_bitdecoder_ctx *bd) {
56403 duk_small_uint_t i;
56404
56405 for (i = 0; i < 8; i++) {
56406 /* Encoding endianness must match target memory layout,
56407 * build scripts and genbuiltins.py must ensure this.
56408 */
56409 du.uc[i] = (duk_uint8_t) duk_bd_decode(bd, 8);
56410 }
56411
56412 duk_push_number(ctx, du.d); /* push operation normalizes NaNs */
56413}
56414
56415DUK_INTERNAL void duk_hthread_create_builtin_objects(duk_hthread *thr) {
56416 duk_context *ctx = (duk_context *) thr;
56417 duk_bitdecoder_ctx bd_ctx;
56418 duk_bitdecoder_ctx *bd = &bd_ctx; /* convenience */
56419 duk_hobject *h;
56420 duk_small_uint_t i, j;
56421
56422 DUK_D(DUK_DPRINT("INITBUILTINS BEGIN: DUK_NUM_BUILTINS=%d, DUK_NUM_BUILTINS_ALL=%d", (int) DUK_NUM_BUILTINS, (int) DUK_NUM_ALL_BUILTINS));
56423
56424 DUK_MEMZERO(&bd_ctx, sizeof(bd_ctx));
56425 bd->data = (const duk_uint8_t *) duk_builtins_data;
56426 bd->length = (duk_size_t) DUK_BUILTINS_DATA_LENGTH;
56427
56428 /*
56429 * First create all built-in bare objects on the empty valstack.
56430 *
56431 * Built-ins in the index range [0,DUK_NUM_BUILTINS-1] have value
56432 * stack indices matching their eventual thr->builtins[] index.
56433 *
56434 * Built-ins in the index range [DUK_NUM_BUILTINS,DUK_NUM_ALL_BUILTINS]
56435 * will exist on the value stack during init but won't be placed
56436 * into thr->builtins[]. These are objects referenced in some way
56437 * from thr->builtins[] roots but which don't need to be indexed by
56438 * Duktape through thr->builtins[] (e.g. user custom objects).
56439 */
56440
56441 duk_require_stack(ctx, DUK_NUM_ALL_BUILTINS);
56442
56443 DUK_DD(DUK_DDPRINT("create empty built-ins"));
56444 DUK_ASSERT_TOP(ctx, 0);
56445 for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
56446 duk_small_uint_t class_num;
56447 duk_small_int_t len = -1; /* must be signed */
56448
56449 class_num = (duk_small_uint_t) duk_bd_decode_varuint(bd);
56450 len = (duk_small_int_t) duk_bd_decode_flagged(bd, DUK__LENGTH_PROP_BITS, (duk_int32_t) -1 /*def_value*/);
56451
56452 if (class_num == DUK_HOBJECT_CLASS_FUNCTION) {
56453 duk_small_uint_t natidx;
56454 duk_int_t c_nargs; /* must hold DUK_VARARGS */
56455 duk_c_function c_func;
56456 duk_int16_t magic;
56457
56458 DUK_DDD(DUK_DDDPRINT("len=%ld", (long) len));
56459 DUK_ASSERT(len >= 0);
56460
56461 natidx = (duk_small_uint_t) duk_bd_decode_varuint(bd);
56462 DUK_ASSERT(natidx != 0);
56463 c_func = duk_bi_native_functions[natidx];
56464 DUK_ASSERT(c_func != NULL);
56465
56466 c_nargs = (duk_small_uint_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, len /*def_value*/);
56467 if (c_nargs == DUK__NARGS_VARARGS_MARKER) {
56468 c_nargs = DUK_VARARGS;
56469 }
56470
56471 /* XXX: set magic directly here? (it could share the c_nargs arg) */
56472 duk_push_c_function_noexotic(ctx, c_func, c_nargs);
56473
56474 h = duk_known_hobject(ctx, -1);
56475
56476 /* Currently all built-in native functions are strict.
56477 * duk_push_c_function() now sets strict flag, so
56478 * assert for it.
56479 */
56480 DUK_ASSERT(DUK_HOBJECT_HAS_STRICT(h));
56481
56482 /* XXX: function properties */
56483
56484 duk__push_stridx_or_string(ctx, bd);
56485#if defined(DUK_USE_FUNC_NAME_PROPERTY)
56486 duk_xdef_prop_stridx_short(ctx,
56487 -2,
56488 DUK_STRIDX_NAME,
56489 DUK_PROPDESC_FLAGS_C);
56490#else
56491 duk_pop(ctx); /* Not very ideal but good enough for now. */
56492#endif
56493
56494 /* Almost all global level Function objects are constructable
56495 * but not all: Function.prototype is a non-constructable,
56496 * callable Function.
56497 */
56498 if (duk_bd_decode_flag(bd)) {
56499 DUK_ASSERT(DUK_HOBJECT_HAS_CONSTRUCTABLE(h));
56500 } else {
56501 DUK_HOBJECT_CLEAR_CONSTRUCTABLE(h);
56502 }
56503
56504 /* Cast converts magic to 16-bit signed value */
56505 magic = (duk_int16_t) duk_bd_decode_varuint(bd);
56506 ((duk_hnatfunc *) h)->magic = magic;
56507 } else if (class_num == DUK_HOBJECT_CLASS_ARRAY) {
56508 duk_push_array(ctx);
56509 } else {
56510 (void) duk_push_object_helper(ctx,
56511 DUK_HOBJECT_FLAG_EXTENSIBLE,
56512 -1); /* no prototype or class yet */
56513
56514 }
56515
56516 h = duk_known_hobject(ctx, -1);
56517 DUK_HOBJECT_SET_CLASS_NUMBER(h, class_num);
56518
56519 if (i < DUK_NUM_BUILTINS) {
56520 thr->builtins[i] = h;
56521 DUK_HOBJECT_INCREF(thr, &h->hdr);
56522 }
56523
56524 if (len >= 0) {
56525 /* In ES2015+ built-in function object .length property
56526 * has property attributes C (configurable only):
56527 * http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-standard-built-in-objects
56528 *
56529 * Array.prototype remains an Array instance in ES2015+
56530 * and its length has attributes W (writable only).
56531 * Because .length is now virtual for duk_harray, it is
56532 * not encoded explicitly in init data.
56533 */
56534
56535 DUK_ASSERT(class_num != DUK_HOBJECT_CLASS_ARRAY); /* .length is virtual */
56536 duk_push_int(ctx, len);
56537 duk_xdef_prop_stridx_short(ctx,
56538 -2,
56539 DUK_STRIDX_LENGTH,
56540 DUK_PROPDESC_FLAGS_C);
56541 }
56542
56543 /* enable exotic behaviors last */
56544
56545 if (class_num == DUK_HOBJECT_CLASS_ARRAY) {
56546 DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(h)); /* set by duk_push_array() */
56547 }
56548 if (class_num == DUK_HOBJECT_CLASS_STRING) {
56549 DUK_HOBJECT_SET_EXOTIC_STRINGOBJ(h);
56550 }
56551
56552 /* some assertions */
56553
56554 DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h));
56555 /* DUK_HOBJECT_FLAG_CONSTRUCTABLE varies */
56556 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(h));
56557 DUK_ASSERT(!DUK_HOBJECT_HAS_COMPFUNC(h));
56558 /* DUK_HOBJECT_FLAG_NATFUNC varies */
56559 DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(h));
56560 DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(h) || class_num == DUK_HOBJECT_CLASS_ARRAY);
56561 /* DUK_HOBJECT_FLAG_STRICT varies */
56562 DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(h) || /* all native functions have NEWENV */
56563 DUK_HOBJECT_HAS_NEWENV(h));
56564 DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(h));
56565 DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(h));
56566 DUK_ASSERT(!DUK_HOBJECT_HAS_ENVRECCLOSED(h));
56567 /* DUK_HOBJECT_FLAG_EXOTIC_ARRAY varies */
56568 /* DUK_HOBJECT_FLAG_EXOTIC_STRINGOBJ varies */
56569 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(h));
56570
56571 DUK_DDD(DUK_DDDPRINT("created built-in %ld, class=%ld, length=%ld", (long) i, (long) class_num, (long) len));
56572 }
56573
56574 /*
56575 * Then decode the builtins init data (see genbuiltins.py) to
56576 * init objects
56577 */
56578
56579 DUK_DD(DUK_DDPRINT("initialize built-in object properties"));
56580 for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
56581 duk_small_uint_t t;
56582 duk_small_uint_t num;
56583
56584 DUK_DDD(DUK_DDDPRINT("initializing built-in object at index %ld", (long) i));
56585 h = duk_known_hobject(ctx, i);
56586
56587 t = (duk_small_uint_t) duk_bd_decode_varuint(bd);
56588 if (t > 0) {
56589 t--;
56590 DUK_DDD(DUK_DDDPRINT("set internal prototype: built-in %ld", (long) t));
56591 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, duk_known_hobject(ctx, t));
56592 }
56593
56594 t = (duk_small_uint_t) duk_bd_decode_varuint(bd);
56595 if (t > 0) {
56596 /* 'prototype' property for all built-in objects (which have it) has attributes:
56597 * [[Writable]] = false,
56598 * [[Enumerable]] = false,
56599 * [[Configurable]] = false
56600 */
56601 t--;
56602 DUK_DDD(DUK_DDDPRINT("set external prototype: built-in %ld", (long) t));
56603 duk_xdef_prop_stridx_builtin(ctx, i, DUK_STRIDX_PROTOTYPE, t, DUK_PROPDESC_FLAGS_NONE);
56604 }
56605
56606 t = (duk_small_uint_t) duk_bd_decode_varuint(bd);
56607 if (t > 0) {
56608 /* 'constructor' property for all built-in objects (which have it) has attributes:
56609 * [[Writable]] = true,
56610 * [[Enumerable]] = false,
56611 * [[Configurable]] = true
56612 */
56613 t--;
56614 DUK_DDD(DUK_DDDPRINT("set external constructor: built-in %ld", (long) t));
56615 duk_xdef_prop_stridx_builtin(ctx, i, DUK_STRIDX_CONSTRUCTOR, t, DUK_PROPDESC_FLAGS_WC);
56616 }
56617
56618 /* normal valued properties */
56619 num = (duk_small_uint_t) duk_bd_decode_varuint(bd);
56620 DUK_DDD(DUK_DDDPRINT("built-in object %ld, %ld normal valued properties", (long) i, (long) num));
56621 for (j = 0; j < num; j++) {
56622 duk_small_uint_t defprop_flags;
56623
56624 duk__push_stridx_or_string(ctx, bd);
56625
56626 /*
56627 * Property attribute defaults are defined in E5 Section 15 (first
56628 * few pages); there is a default for all properties and a special
56629 * default for 'length' properties. Variation from the defaults is
56630 * signaled using a single flag bit in the bitstream.
56631 */
56632
56633 if (duk_bd_decode_flag(bd)) {
56634 defprop_flags = (duk_small_uint_t) duk_bd_decode(bd, DUK__PROP_FLAGS_BITS);
56635 } else {
56636 defprop_flags = DUK_PROPDESC_FLAGS_WC;
56637 }
56638 defprop_flags |= DUK_DEFPROP_FORCE |
56639 DUK_DEFPROP_HAVE_VALUE |
56640 DUK_DEFPROP_HAVE_WRITABLE |
56641 DUK_DEFPROP_HAVE_ENUMERABLE |
56642 DUK_DEFPROP_HAVE_CONFIGURABLE; /* Defaults for data properties. */
56643
56644 /* The writable, enumerable, configurable flags in prop_flags
56645 * match both duk_def_prop() and internal property flags.
56646 */
56647 DUK_ASSERT(DUK_PROPDESC_FLAG_WRITABLE == DUK_DEFPROP_WRITABLE);
56648 DUK_ASSERT(DUK_PROPDESC_FLAG_ENUMERABLE == DUK_DEFPROP_ENUMERABLE);
56649 DUK_ASSERT(DUK_PROPDESC_FLAG_CONFIGURABLE == DUK_DEFPROP_CONFIGURABLE);
56650
56651 t = (duk_small_uint_t) duk_bd_decode(bd, DUK__PROP_TYPE_BITS);
56652
56653 DUK_DDD(DUK_DDDPRINT("built-in %ld, normal-valued property %ld, key %!T, flags 0x%02lx, type %ld",
56654 (long) i, (long) j, duk_get_tval(ctx, -1), (unsigned long) defprop_flags, (long) t));
56655
56656 switch (t) {
56657 case DUK__PROP_TYPE_DOUBLE: {
56658 duk__push_double(ctx, bd);
56659 break;
56660 }
56661 case DUK__PROP_TYPE_STRING: {
56662 duk__push_string(ctx, bd);
56663 break;
56664 }
56665 case DUK__PROP_TYPE_STRIDX: {
56666 duk__push_stridx(ctx, bd);
56667 break;
56668 }
56669 case DUK__PROP_TYPE_BUILTIN: {
56670 duk_small_uint_t bidx;
56671
56672 bidx = (duk_small_uint_t) duk_bd_decode_varuint(bd);
56673 duk_dup(ctx, (duk_idx_t) bidx);
56674 break;
56675 }
56676 case DUK__PROP_TYPE_UNDEFINED: {
56677 duk_push_undefined(ctx);
56678 break;
56679 }
56680 case DUK__PROP_TYPE_BOOLEAN_TRUE: {
56681 duk_push_true(ctx);
56682 break;
56683 }
56684 case DUK__PROP_TYPE_BOOLEAN_FALSE: {
56685 duk_push_false(ctx);
56686 break;
56687 }
56688 case DUK__PROP_TYPE_ACCESSOR: {
56689 duk_small_uint_t natidx_getter = (duk_small_uint_t) duk_bd_decode_varuint(bd);
56690 duk_small_uint_t natidx_setter = (duk_small_uint_t) duk_bd_decode_varuint(bd);
56691 duk_small_uint_t accessor_magic = (duk_small_uint_t) duk_bd_decode_varuint(bd);
56692 duk_c_function c_func_getter;
56693 duk_c_function c_func_setter;
56694
56695 DUK_DDD(DUK_DDDPRINT("built-in accessor property: objidx=%ld, key=%!T, getteridx=%ld, setteridx=%ld, flags=0x%04lx",
56696 (long) i, duk_get_tval(ctx, -1), (long) natidx_getter, (long) natidx_setter, (unsigned long) defprop_flags));
56697
56698 c_func_getter = duk_bi_native_functions[natidx_getter];
56699 if (c_func_getter != NULL) {
56700 duk_push_c_function_noconstruct_noexotic(ctx, c_func_getter, 0); /* always 0 args */
56701 duk_set_magic(ctx, -1, (duk_int_t) accessor_magic);
56702 defprop_flags |= DUK_DEFPROP_HAVE_GETTER;
56703 }
56704 c_func_setter = duk_bi_native_functions[natidx_setter];
56705 if (c_func_setter != NULL) {
56706 duk_push_c_function_noconstruct_noexotic(ctx, c_func_setter, 1); /* always 1 arg */
56707 duk_set_magic(ctx, -1, (duk_int_t) accessor_magic);
56708 defprop_flags |= DUK_DEFPROP_HAVE_SETTER;
56709 }
56710
56711 /* Writable flag doesn't make sense for an accessor. */
56712 DUK_ASSERT((defprop_flags & DUK_PROPDESC_FLAG_WRITABLE) == 0); /* genbuiltins.py ensures */
56713
56714 defprop_flags &= ~(DUK_DEFPROP_HAVE_VALUE | DUK_DEFPROP_HAVE_WRITABLE);
56715 defprop_flags |= DUK_DEFPROP_HAVE_ENUMERABLE | DUK_DEFPROP_HAVE_CONFIGURABLE;
56716 break;
56717 }
56718 default: {
56719 /* exhaustive */
56720 DUK_UNREACHABLE();
56721 }
56722 }
56723
56724 duk_def_prop(ctx, i, defprop_flags);
56725 DUK_ASSERT_TOP(ctx, DUK_NUM_ALL_BUILTINS);
56726 }
56727
56728 /* native function properties */
56729 num = (duk_small_uint_t) duk_bd_decode_varuint(bd);
56730 DUK_DDD(DUK_DDDPRINT("built-in object %ld, %ld function valued properties", (long) i, (long) num));
56731 for (j = 0; j < num; j++) {
56732 duk_hstring *h_key;
56733 duk_small_uint_t natidx;
56734 duk_int_t c_nargs; /* must hold DUK_VARARGS */
56735 duk_small_uint_t c_length;
56736 duk_int16_t magic;
56737 duk_c_function c_func;
56738 duk_hnatfunc *h_func;
56739#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
56740 duk_small_int_t lightfunc_eligible;
56741#endif
56742
56743 duk__push_stridx_or_string(ctx, bd);
56744 h_key = duk_known_hstring(ctx, -1);
56745 DUK_UNREF(h_key);
56746 natidx = (duk_small_uint_t) duk_bd_decode_varuint(bd);
56747
56748 c_length = (duk_small_uint_t) duk_bd_decode(bd, DUK__LENGTH_PROP_BITS);
56749 c_nargs = (duk_int_t) duk_bd_decode_flagged(bd, DUK__NARGS_BITS, (duk_int32_t) c_length /*def_value*/);
56750 if (c_nargs == DUK__NARGS_VARARGS_MARKER) {
56751 c_nargs = DUK_VARARGS;
56752 }
56753
56754 c_func = duk_bi_native_functions[natidx];
56755
56756 DUK_DDD(DUK_DDDPRINT("built-in %ld, function-valued property %ld, key %!O, natidx %ld, length %ld, nargs %ld",
56757 (long) i, (long) j, (duk_heaphdr *) h_key, (long) natidx, (long) c_length,
56758 (c_nargs == DUK_VARARGS ? (long) -1 : (long) c_nargs)));
56759
56760 /* Cast converts magic to 16-bit signed value */
56761 magic = (duk_int16_t) duk_bd_decode_varuint(bd);
56762
56763#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
56764 lightfunc_eligible =
56765 ((c_nargs >= DUK_LFUNC_NARGS_MIN && c_nargs <= DUK_LFUNC_NARGS_MAX) || (c_nargs == DUK_VARARGS)) &&
56766 (c_length <= DUK_LFUNC_LENGTH_MAX) &&
56767 (magic >= DUK_LFUNC_MAGIC_MIN && magic <= DUK_LFUNC_MAGIC_MAX);
56768
56769 if (h_key == DUK_HTHREAD_STRING_EVAL(thr) ||
56770 h_key == DUK_HTHREAD_STRING_YIELD(thr) ||
56771 h_key == DUK_HTHREAD_STRING_RESUME(thr)) {
56772 /* These functions have trouble working as lightfuncs.
56773 * Some of them have specific asserts and some may have
56774 * additional properties (e.g. 'require.id' may be written).
56775 */
56776 DUK_D(DUK_DPRINT("reject as lightfunc: key=%!O, i=%d, j=%d", (duk_heaphdr *) h_key, (int) i, (int) j));
56777 lightfunc_eligible = 0;
56778 }
56779
56780 if (lightfunc_eligible) {
56781 duk_tval tv_lfunc;
56782 duk_small_uint_t lf_nargs = (c_nargs == DUK_VARARGS ? DUK_LFUNC_NARGS_VARARGS : c_nargs);
56783 duk_small_uint_t lf_flags = DUK_LFUNC_FLAGS_PACK(magic, c_length, lf_nargs);
56784 DUK_TVAL_SET_LIGHTFUNC(&tv_lfunc, c_func, lf_flags);
56785 duk_push_tval(ctx, &tv_lfunc);
56786 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(ctx, -1)));
56787 goto lightfunc_skip;
56788 }
56789
56790 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));
56791#endif /* DUK_USE_LIGHTFUNC_BUILTINS */
56792
56793 /* [ (builtin objects) name ] */
56794
56795 duk_push_c_function_noconstruct_noexotic(ctx, c_func, c_nargs);
56796 h_func = duk_known_hnatfunc(ctx, -1);
56797 DUK_UNREF(h_func);
56798
56799 /* Currently all built-in native functions are strict.
56800 * This doesn't matter for many functions, but e.g.
56801 * String.prototype.charAt (and other string functions)
56802 * rely on being strict so that their 'this' binding is
56803 * not automatically coerced.
56804 */
56805 DUK_HOBJECT_SET_STRICT((duk_hobject *) h_func);
56806
56807 /* No built-in functions are constructable except the top
56808 * level ones (Number, etc).
56809 */
56810 DUK_ASSERT(!DUK_HOBJECT_HAS_CONSTRUCTABLE((duk_hobject *) h_func));
56811
56812 /* XXX: any way to avoid decoding magic bit; there are quite
56813 * many function properties and relatively few with magic values.
56814 */
56815 h_func->magic = magic;
56816
56817 /* [ (builtin objects) name func ] */
56818
56819 duk_push_int(ctx, c_length);
56820 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C);
56821
56822 duk_dup_m2(ctx);
56823 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C);
56824
56825 /* XXX: other properties of function instances; 'arguments', 'caller'. */
56826
56827 DUK_DD(DUK_DDPRINT("built-in object %ld, function property %ld -> %!T",
56828 (long) i, (long) j, (duk_tval *) duk_get_tval(ctx, -1)));
56829
56830 /* [ (builtin objects) name func ] */
56831
56832 /*
56833 * The default property attributes are correct for all
56834 * function valued properties of built-in objects now.
56835 */
56836
56837#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
56838 lightfunc_skip:
56839#endif
56840
56841 duk_xdef_prop(ctx, i, DUK_PROPDESC_FLAGS_WC);
56842
56843 /* [ (builtin objects) ] */
56844 }
56845 }
56846
56847 /*
56848 * Special post-tweaks, for cases not covered by the init data format.
56849 *
56850 * - Set Date.prototype.toGMTString to Date.prototype.toUTCString.
56851 * toGMTString is required to have the same Function object as
56852 * toUTCString in E5 Section B.2.6. Note that while Smjs respects
56853 * this, V8 does not (the Function objects are distinct).
56854 *
56855 * - Make DoubleError non-extensible.
56856 *
56857 * - Add info about most important effective compile options to Duktape.
56858 *
56859 * - Possibly remove some properties (values or methods) which are not
56860 * desirable with current feature options but are not currently
56861 * conditional in init data.
56862 */
56863
56864#if defined(DUK_USE_DATE_BUILTIN)
56865 duk_get_prop_stridx_short(ctx, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_UTC_STRING);
56866 duk_xdef_prop_stridx_short(ctx, DUK_BIDX_DATE_PROTOTYPE, DUK_STRIDX_TO_GMT_STRING, DUK_PROPDESC_FLAGS_WC);
56867#endif
56868
56869 h = duk_known_hobject(ctx, DUK_BIDX_DOUBLE_ERROR);
56870 DUK_HOBJECT_CLEAR_EXTENSIBLE(h);
56871
56872#if !defined(DUK_USE_ES6_OBJECT_PROTO_PROPERTY)
56873 DUK_DD(DUK_DDPRINT("delete Object.prototype.__proto__ built-in which is not enabled in features"));
56874 (void) duk_hobject_delprop_raw(thr, thr->builtins[DUK_BIDX_OBJECT_PROTOTYPE], DUK_HTHREAD_STRING___PROTO__(thr), DUK_DELPROP_FLAG_THROW);
56875#endif
56876
56877#if !defined(DUK_USE_ES6_OBJECT_SETPROTOTYPEOF)
56878 DUK_DD(DUK_DDPRINT("delete Object.setPrototypeOf built-in which is not enabled in features"));
56879 (void) duk_hobject_delprop_raw(thr, thr->builtins[DUK_BIDX_OBJECT_CONSTRUCTOR], DUK_HTHREAD_STRING_SET_PROTOTYPE_OF(thr), DUK_DELPROP_FLAG_THROW);
56880#endif
56881
56882 /* XXX: relocate */
56883 duk_push_string(ctx,
56884 /* Endianness indicator */
56885#if defined(DUK_USE_INTEGER_LE)
56886 "l"
56887#elif defined(DUK_USE_INTEGER_BE)
56888 "b"
56889#elif defined(DUK_USE_INTEGER_ME) /* integer mixed endian not really used now */
56890 "m"
56891#else
56892 "?"
56893#endif
56894#if defined(DUK_USE_DOUBLE_LE)
56895 "l"
56896#elif defined(DUK_USE_DOUBLE_BE)
56897 "b"
56898#elif defined(DUK_USE_DOUBLE_ME)
56899 "m"
56900#else
56901 "?"
56902#endif
56903 " "
56904 /* Packed or unpacked tval */
56905#if defined(DUK_USE_PACKED_TVAL)
56906 "p"
56907#else
56908 "u"
56909#endif
56910#if defined(DUK_USE_FASTINT)
56911 "f"
56912#endif
56913 " "
56914 /* Low memory options */
56915#if defined(DUK_USE_STRTAB_CHAIN)
56916 "c" /* chain */
56917#elif defined(DUK_USE_STRTAB_PROBE)
56918 "p" /* probe */
56919#else
56920 "?"
56921#endif
56922#if !defined(DUK_USE_HEAPPTR16) && !defined(DUK_DATAPTR16) && !defined(DUK_FUNCPTR16)
56923 "n"
56924#endif
56925#if defined(DUK_USE_HEAPPTR16)
56926 "h"
56927#endif
56928#if defined(DUK_USE_DATAPTR16)
56929 "d"
56930#endif
56931#if defined(DUK_USE_FUNCPTR16)
56932 "f"
56933#endif
56934#if defined(DUK_USE_REFCOUNT16)
56935 "R"
56936#endif
56937#if defined(DUK_USE_STRHASH16)
56938 "H"
56939#endif
56940#if defined(DUK_USE_STRLEN16)
56941 "S"
56942#endif
56943#if defined(DUK_USE_BUFLEN16)
56944 "B"
56945#endif
56946#if defined(DUK_USE_OBJSIZES16)
56947 "O"
56948#endif
56949#if defined(DUK_USE_LIGHTFUNC_BUILTINS)
56950 "L"
56951#endif
56952#if defined(DUK_USE_ROM_STRINGS) || defined(DUK_USE_ROM_OBJECTS)
56953 /* XXX: This won't be shown in practice now
56954 * because this code is not run when builtins
56955 * are in ROM.
56956 */
56957 "Z"
56958#endif
56959 " "
56960 /* Object property allocation layout */
56961#if defined(DUK_USE_HOBJECT_LAYOUT_1)
56962 "p1"
56963#elif defined(DUK_USE_HOBJECT_LAYOUT_2)
56964 "p2"
56965#elif defined(DUK_USE_HOBJECT_LAYOUT_3)
56966 "p3"
56967#else
56968 "p?"
56969#endif
56970 " "
56971 /* Alignment guarantee */
56972#if (DUK_USE_ALIGN_BY == 4)
56973 "a4"
56974#elif (DUK_USE_ALIGN_BY == 8)
56975 "a8"
56976#elif (DUK_USE_ALIGN_BY == 1)
56977 "a1"
56978#else
56979#error invalid DUK_USE_ALIGN_BY
56980#endif
56981 " "
56982 /* Architecture, OS, and compiler strings */
56983 DUK_USE_ARCH_STRING
56984 " "
56985 DUK_USE_OS_STRING
56986 " "
56987 DUK_USE_COMPILER_STRING);
56988 duk_xdef_prop_stridx_short(ctx, DUK_BIDX_DUKTAPE, DUK_STRIDX_ENV, DUK_PROPDESC_FLAGS_WC);
56989
56990 /*
56991 * Since built-ins are not often extended, compact them.
56992 */
56993
56994 DUK_DD(DUK_DDPRINT("compact built-ins"));
56995 for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
56996 duk_hobject_compact_props(thr, duk_known_hobject(ctx, i));
56997 }
56998
56999 DUK_D(DUK_DPRINT("INITBUILTINS END"));
57000
57001#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 1)
57002 for (i = 0; i < DUK_NUM_ALL_BUILTINS; i++) {
57003 DUK_DD(DUK_DDPRINT("built-in object %ld after initialization and compacting: %!@iO",
57004 (long) i, (duk_heaphdr *) duk_require_hobject(ctx, i)));
57005 }
57006#endif
57007
57008 /*
57009 * Pop built-ins from stack: they are now INCREF'd and
57010 * reachable from the builtins[] array or indirectly
57011 * through builtins[].
57012 */
57013
57014 duk_set_top(ctx, 0);
57015 DUK_ASSERT_TOP(ctx, 0);
57016}
57017#endif /* DUK_USE_ROM_OBJECTS */
57018
57019DUK_INTERNAL void duk_hthread_copy_builtin_objects(duk_hthread *thr_from, duk_hthread *thr_to) {
57020 duk_small_uint_t i;
57021
57022 for (i = 0; i < DUK_NUM_BUILTINS; i++) {
57023 thr_to->builtins[i] = thr_from->builtins[i];
57024 DUK_HOBJECT_INCREF_ALLOWNULL(thr_to, thr_to->builtins[i]); /* side effect free */
57025 }
57026}
57027
57028/* automatic undefs */
57029#undef DUK__LENGTH_PROP_BITS
57030#undef DUK__NARGS_BITS
57031#undef DUK__NARGS_VARARGS_MARKER
57032#undef DUK__PROP_FLAGS_BITS
57033#undef DUK__PROP_TYPE_ACCESSOR
57034#undef DUK__PROP_TYPE_BITS
57035#undef DUK__PROP_TYPE_BOOLEAN_FALSE
57036#undef DUK__PROP_TYPE_BOOLEAN_TRUE
57037#undef DUK__PROP_TYPE_BUILTIN
57038#undef DUK__PROP_TYPE_DOUBLE
57039#undef DUK__PROP_TYPE_STRIDX
57040#undef DUK__PROP_TYPE_STRING
57041#undef DUK__PROP_TYPE_UNDEFINED
57042/*
57043 * Thread support.
57044 */
57045
57046/* #include duk_internal.h -> already included */
57047
57048DUK_INTERNAL void duk_hthread_terminate(duk_hthread *thr) {
57049 DUK_ASSERT(thr != NULL);
57050
57051 /* Order of unwinding is important */
57052
57053 duk_hthread_catchstack_unwind(thr, 0);
57054
57055 duk_hthread_callstack_unwind(thr, 0); /* side effects, possibly errors */
57056
57057 thr->valstack_bottom = thr->valstack;
57058 duk_set_top((duk_context *) thr, 0); /* unwinds valstack, updating refcounts */
57059
57060 thr->state = DUK_HTHREAD_STATE_TERMINATED;
57061
57062 /* Here we could remove references to built-ins, but it may not be
57063 * worth the effort because built-ins are quite likely to be shared
57064 * with another (unterminated) thread, and terminated threads are also
57065 * usually garbage collected quite quickly. Also, doing DECREFs
57066 * could trigger finalization, which would run on the current thread
57067 * and have access to only some of the built-ins. Garbage collection
57068 * deals with this correctly already.
57069 */
57070
57071 /* XXX: Shrink the stacks to minimize memory usage? May not
57072 * be worth the effort because terminated threads are usually
57073 * garbage collected quite soon.
57074 */
57075}
57076
57077DUK_INTERNAL duk_activation *duk_hthread_get_current_activation(duk_hthread *thr) {
57078 DUK_ASSERT(thr != NULL);
57079
57080 if (thr->callstack_top > 0) {
57081 return thr->callstack + thr->callstack_top - 1;
57082 } else {
57083 return NULL;
57084 }
57085}
57086
57087#if defined(DUK_USE_DEBUGGER_SUPPORT)
57088DUK_INTERNAL duk_uint_fast32_t duk_hthread_get_act_curr_pc(duk_hthread *thr, duk_activation *act) {
57089 duk_instr_t *bcode;
57090
57091 DUK_ASSERT(thr != NULL);
57092 DUK_ASSERT(act != NULL);
57093 DUK_UNREF(thr);
57094
57095 /* XXX: store 'bcode' pointer to activation for faster lookup? */
57096 if (act->func && DUK_HOBJECT_IS_COMPFUNC(act->func)) {
57097 bcode = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) (act->func));
57098 return (duk_uint_fast32_t) (act->curr_pc - bcode);
57099 }
57100 return 0;
57101}
57102#endif /* DUK_USE_DEBUGGER_SUPPORT */
57103
57104DUK_INTERNAL duk_uint_fast32_t duk_hthread_get_act_prev_pc(duk_hthread *thr, duk_activation *act) {
57105 duk_instr_t *bcode;
57106 duk_uint_fast32_t ret;
57107
57108 DUK_ASSERT(thr != NULL);
57109 DUK_ASSERT(act != NULL);
57110 DUK_UNREF(thr);
57111
57112 if (act->func && DUK_HOBJECT_IS_COMPFUNC(act->func)) {
57113 bcode = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) (act->func));
57114 ret = (duk_uint_fast32_t) (act->curr_pc - bcode);
57115 if (ret > 0) {
57116 ret--;
57117 }
57118 return ret;
57119 }
57120 return 0;
57121}
57122
57123/* Write bytecode executor's curr_pc back to topmost activation (if any). */
57124DUK_INTERNAL void duk_hthread_sync_currpc(duk_hthread *thr) {
57125 duk_activation *act;
57126
57127 DUK_ASSERT(thr != NULL);
57128
57129 if (thr->ptr_curr_pc != NULL) {
57130 /* ptr_curr_pc != NULL only when bytecode executor is active. */
57131 DUK_ASSERT(thr->callstack_top > 0);
57132 act = thr->callstack + thr->callstack_top - 1;
57133 act->curr_pc = *thr->ptr_curr_pc;
57134 }
57135}
57136
57137DUK_INTERNAL void duk_hthread_sync_and_null_currpc(duk_hthread *thr) {
57138 duk_activation *act;
57139
57140 DUK_ASSERT(thr != NULL);
57141
57142 if (thr->ptr_curr_pc != NULL) {
57143 /* ptr_curr_pc != NULL only when bytecode executor is active. */
57144 DUK_ASSERT(thr->callstack_top > 0);
57145 act = thr->callstack + thr->callstack_top - 1;
57146 act->curr_pc = *thr->ptr_curr_pc;
57147 thr->ptr_curr_pc = NULL;
57148 }
57149}
57150/*
57151 * Manipulation of thread stacks (valstack, callstack, catchstack).
57152 *
57153 * Ideally unwinding of stacks should have no side effects, which would
57154 * then favor separate unwinding and shrink check primitives for each
57155 * stack type. A shrink check may realloc and thus have side effects.
57156 *
57157 * However, currently callstack unwinding itself has side effects, as it
57158 * needs to DECREF multiple objects, close environment records, etc.
57159 * Stacks must thus be unwound in the correct order by the caller.
57160 *
57161 * (XXX: This should be probably reworked so that there is a shared
57162 * unwind primitive which handles all stacks as requested, and knows
57163 * the proper order for unwinding.)
57164 *
57165 * Valstack entries above 'top' are always kept initialized to
57166 * "undefined unused". Callstack and catchstack entries above 'top'
57167 * are not zeroed and are left as garbage.
57168 *
57169 * Value stack handling is mostly a part of the API implementation.
57170 */
57171
57172/* #include duk_internal.h -> already included */
57173
57174/* check that there is space for at least one new entry */
57175DUK_INTERNAL void duk_hthread_callstack_grow(duk_hthread *thr) {
57176 duk_activation *new_ptr;
57177 duk_size_t old_size;
57178 duk_size_t new_size;
57179
57180 DUK_ASSERT(thr != NULL);
57181 DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */
57182 DUK_ASSERT(thr->callstack_size >= thr->callstack_top);
57183
57184 if (thr->callstack_top < thr->callstack_size) {
57185 return;
57186 }
57187
57188 old_size = thr->callstack_size;
57189 new_size = old_size + DUK_CALLSTACK_GROW_STEP;
57190
57191 /* this is a bit approximate (errors out before max is reached); this is OK */
57192 if (new_size >= thr->callstack_max) {
57193 DUK_ERROR_RANGE(thr, DUK_STR_CALLSTACK_LIMIT);
57194 }
57195
57196 DUK_DD(DUK_DDPRINT("growing callstack %ld -> %ld", (long) old_size, (long) new_size));
57197
57198 /*
57199 * Note: must use indirect variant of DUK_REALLOC() because underlying
57200 * pointer may be changed by mark-and-sweep.
57201 */
57202
57203 DUK_ASSERT(new_size > 0);
57204 new_ptr = (duk_activation *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_callstack_ptr, (void *) thr, sizeof(duk_activation) * new_size);
57205 if (!new_ptr) {
57206 /* No need for a NULL/zero-size check because new_size > 0) */
57207 DUK_ERROR_ALLOC_FAILED(thr);
57208 }
57209 thr->callstack = new_ptr;
57210 thr->callstack_size = new_size;
57211
57212 /* note: any entries above the callstack top are garbage and not zeroed */
57213}
57214
57215DUK_INTERNAL void duk_hthread_callstack_shrink_check(duk_hthread *thr) {
57216 duk_size_t new_size;
57217 duk_activation *p;
57218
57219 DUK_ASSERT(thr != NULL);
57220 DUK_ASSERT_DISABLE(thr->callstack_top >= 0); /* avoid warning (unsigned) */
57221 DUK_ASSERT(thr->callstack_size >= thr->callstack_top);
57222
57223 if (thr->callstack_size - thr->callstack_top < DUK_CALLSTACK_SHRINK_THRESHOLD) {
57224 return;
57225 }
57226
57227 new_size = thr->callstack_top + DUK_CALLSTACK_SHRINK_SPARE;
57228 DUK_ASSERT(new_size >= thr->callstack_top);
57229
57230 DUK_DD(DUK_DDPRINT("shrinking callstack %ld -> %ld", (long) thr->callstack_size, (long) new_size));
57231
57232 /*
57233 * Note: must use indirect variant of DUK_REALLOC() because underlying
57234 * pointer may be changed by mark-and-sweep.
57235 */
57236
57237 /* shrink failure is not fatal */
57238 p = (duk_activation *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_callstack_ptr, (void *) thr, sizeof(duk_activation) * new_size);
57239 if (p) {
57240 thr->callstack = p;
57241 thr->callstack_size = new_size;
57242 } else {
57243 /* Because new_size != 0, if condition doesn't need to be
57244 * (p != NULL || new_size == 0).
57245 */
57246 DUK_ASSERT(new_size != 0);
57247 DUK_D(DUK_DPRINT("callstack shrink failed, ignoring"));
57248 }
57249
57250 /* note: any entries above the callstack top are garbage and not zeroed */
57251}
57252
57253DUK_INTERNAL void duk_hthread_callstack_unwind(duk_hthread *thr, duk_size_t new_top) {
57254 duk_size_t idx;
57255
57256 DUK_DDD(DUK_DDDPRINT("unwind callstack top of thread %p from %ld to %ld",
57257 (void *) thr,
57258 (thr != NULL ? (long) thr->callstack_top : (long) -1),
57259 (long) new_top));
57260
57261 DUK_ASSERT(thr);
57262 DUK_ASSERT(thr->heap);
57263 DUK_ASSERT_DISABLE(new_top >= 0); /* unsigned */
57264 DUK_ASSERT((duk_size_t) new_top <= thr->callstack_top); /* cannot grow */
57265
57266 /*
57267 * The loop below must avoid issues with potential callstack
57268 * reallocations. A resize (and other side effects) may happen
57269 * e.g. due to finalizer/errhandler calls caused by a refzero or
57270 * mark-and-sweep. Arbitrary finalizers may run, because when
57271 * an environment record is refzero'd, it may refer to arbitrary
57272 * values which also become refzero'd.
57273 *
57274 * So, the pointer 'p' is re-looked-up below whenever a side effect
57275 * might have changed it.
57276 */
57277
57278 idx = thr->callstack_top;
57279 while (idx > new_top) {
57280 duk_activation *act;
57281 duk_hobject *func;
57282#if defined(DUK_USE_REFERENCE_COUNTING)
57283 duk_hobject *tmp;
57284#endif
57285#if defined(DUK_USE_DEBUGGER_SUPPORT)
57286 duk_heap *heap;
57287#endif
57288
57289 idx--;
57290 DUK_ASSERT_DISABLE(idx >= 0); /* unsigned */
57291 DUK_ASSERT((duk_size_t) idx < thr->callstack_size); /* true, despite side effect resizes */
57292
57293 act = thr->callstack + idx;
57294 /* With lightfuncs, act 'func' may be NULL */
57295
57296#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
57297 /*
57298 * Restore 'caller' property for non-strict callee functions.
57299 */
57300
57301 func = DUK_ACT_GET_FUNC(act);
57302 if (func != NULL && !DUK_HOBJECT_HAS_STRICT(func)) {
57303 duk_tval *tv_caller;
57304 duk_tval tv_tmp;
57305 duk_hobject *h_tmp;
57306
57307 tv_caller = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_CALLER(thr));
57308
57309 /* The act->prev_caller should only be set if the entry for 'caller'
57310 * exists (as it is only set in that case, and the property is not
57311 * configurable), but handle all the cases anyway.
57312 */
57313
57314 if (tv_caller) {
57315 DUK_TVAL_SET_TVAL(&tv_tmp, tv_caller);
57316 if (act->prev_caller) {
57317 /* Just transfer the refcount from act->prev_caller to tv_caller,
57318 * so no need for a refcount update. This is the expected case.
57319 */
57320 DUK_TVAL_SET_OBJECT(tv_caller, act->prev_caller);
57321 act->prev_caller = NULL;
57322 } else {
57323 DUK_TVAL_SET_NULL(tv_caller); /* no incref needed */
57324 DUK_ASSERT(act->prev_caller == NULL);
57325 }
57326 DUK_TVAL_DECREF(thr, &tv_tmp); /* side effects */
57327 } else {
57328 h_tmp = act->prev_caller;
57329 if (h_tmp) {
57330 act->prev_caller = NULL;
57331 DUK_HOBJECT_DECREF(thr, h_tmp); /* side effects */
57332 }
57333 }
57334 act = thr->callstack + idx; /* avoid side effects */
57335 DUK_ASSERT(act->prev_caller == NULL);
57336 }
57337#endif
57338
57339 /*
57340 * Unwind debugger state. If we unwind while stepping
57341 * (either step over or step into), pause execution.
57342 */
57343
57344#if defined(DUK_USE_DEBUGGER_SUPPORT)
57345 heap = thr->heap;
57346 if (heap->dbg_step_thread == thr &&
57347 heap->dbg_step_csindex == idx) {
57348 /* Pause for all step types: step into, step over, step out.
57349 * This is the only place explicitly handling a step out.
57350 */
57351 DUK_HEAP_SET_PAUSED(heap);
57352 DUK_ASSERT(heap->dbg_step_thread == NULL);
57353 }
57354#endif
57355
57356 /*
57357 * Close environment record(s) if they exist.
57358 *
57359 * Only variable environments are closed. If lex_env != var_env, it
57360 * cannot currently contain any register bound declarations.
57361 *
57362 * Only environments created for a NEWENV function are closed. If an
57363 * environment is created for e.g. an eval call, it must not be closed.
57364 */
57365
57366 func = DUK_ACT_GET_FUNC(act);
57367 if (func != NULL && !DUK_HOBJECT_HAS_NEWENV(func)) {
57368 DUK_DDD(DUK_DDDPRINT("skip closing environments, envs not owned by this activation"));
57369 goto skip_env_close;
57370 }
57371 /* func is NULL for lightfunc */
57372
57373 DUK_ASSERT(act->lex_env == act->var_env);
57374 if (act->var_env != NULL) {
57375 DUK_DDD(DUK_DDDPRINT("closing var_env record %p -> %!O",
57376 (void *) act->var_env, (duk_heaphdr *) act->var_env));
57377 duk_js_close_environment_record(thr, act->var_env, func, act->idx_bottom);
57378 act = thr->callstack + idx; /* avoid side effect issues */
57379 }
57380
57381#if 0
57382 if (act->lex_env != NULL) {
57383 if (act->lex_env == act->var_env) {
57384 /* common case, already closed, so skip */
57385 DUK_DD(DUK_DDPRINT("lex_env and var_env are the same and lex_env "
57386 "already closed -> skip closing lex_env"));
57387 ;
57388 } else {
57389 DUK_DD(DUK_DDPRINT("closing lex_env record %p -> %!O",
57390 (void *) act->lex_env, (duk_heaphdr *) act->lex_env));
57391 duk_js_close_environment_record(thr, act->lex_env, DUK_ACT_GET_FUNC(act), act->idx_bottom);
57392 act = thr->callstack + idx; /* avoid side effect issues */
57393 }
57394 }
57395#endif
57396
57397 DUK_ASSERT((act->lex_env == NULL) ||
57398 ((duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL) &&
57399 (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_VARMAP(thr)) == NULL) &&
57400 (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL) &&
57401 (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->lex_env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL)));
57402
57403 DUK_ASSERT((act->var_env == NULL) ||
57404 ((duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL) &&
57405 (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_VARMAP(thr)) == NULL) &&
57406 (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL) &&
57407 (duk_hobject_find_existing_entry_tval_ptr(thr->heap, act->var_env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL)));
57408
57409 skip_env_close:
57410
57411 /*
57412 * Update preventcount
57413 */
57414
57415 if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
57416 DUK_ASSERT(thr->callstack_preventcount >= 1);
57417 thr->callstack_preventcount--;
57418 }
57419
57420 /*
57421 * Reference count updates
57422 *
57423 * Note: careful manipulation of refcounts. The top is
57424 * not updated yet, so all the activations are reachable
57425 * for mark-and-sweep (which may be triggered by decref).
57426 * However, the pointers are NULL so this is not an issue.
57427 */
57428
57429#if defined(DUK_USE_REFERENCE_COUNTING)
57430 tmp = act->var_env;
57431#endif
57432 act->var_env = NULL;
57433#if defined(DUK_USE_REFERENCE_COUNTING)
57434 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
57435 act = thr->callstack + idx; /* avoid side effect issues */
57436#endif
57437
57438#if defined(DUK_USE_REFERENCE_COUNTING)
57439 tmp = act->lex_env;
57440#endif
57441 act->lex_env = NULL;
57442#if defined(DUK_USE_REFERENCE_COUNTING)
57443 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
57444 act = thr->callstack + idx; /* avoid side effect issues */
57445#endif
57446
57447 /* Note: this may cause a corner case situation where a finalizer
57448 * may see a currently reachable activation whose 'func' is NULL.
57449 */
57450#if defined(DUK_USE_REFERENCE_COUNTING)
57451 tmp = DUK_ACT_GET_FUNC(act);
57452#endif
57453 act->func = NULL;
57454#if defined(DUK_USE_REFERENCE_COUNTING)
57455 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
57456 act = thr->callstack + idx; /* avoid side effect issues */
57457 DUK_UNREF(act);
57458#endif
57459 }
57460
57461 thr->callstack_top = new_top;
57462
57463 /*
57464 * We could clear the book-keeping variables for the topmost activation,
57465 * but don't do so now.
57466 */
57467#if 0
57468 if (thr->callstack_top > 0) {
57469 duk_activation *act = thr->callstack + thr->callstack_top - 1;
57470 act->idx_retval = 0;
57471 }
57472#endif
57473
57474 /* Note: any entries above the callstack top are garbage and not zeroed.
57475 * Also topmost activation idx_retval is garbage (not zeroed), and must
57476 * be ignored.
57477 */
57478}
57479
57480DUK_INTERNAL void duk_hthread_catchstack_grow(duk_hthread *thr) {
57481 duk_catcher *new_ptr;
57482 duk_size_t old_size;
57483 duk_size_t new_size;
57484
57485 DUK_ASSERT(thr != NULL);
57486 DUK_ASSERT_DISABLE(thr->catchstack_top); /* avoid warning (unsigned) */
57487 DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top);
57488
57489 if (thr->catchstack_top < thr->catchstack_size) {
57490 return;
57491 }
57492
57493 old_size = thr->catchstack_size;
57494 new_size = old_size + DUK_CATCHSTACK_GROW_STEP;
57495
57496 /* this is a bit approximate (errors out before max is reached); this is OK */
57497 if (new_size >= thr->catchstack_max) {
57498 DUK_ERROR_RANGE(thr, DUK_STR_CATCHSTACK_LIMIT);
57499 }
57500
57501 DUK_DD(DUK_DDPRINT("growing catchstack %ld -> %ld", (long) old_size, (long) new_size));
57502
57503 /*
57504 * Note: must use indirect variant of DUK_REALLOC() because underlying
57505 * pointer may be changed by mark-and-sweep.
57506 */
57507
57508 DUK_ASSERT(new_size > 0);
57509 new_ptr = (duk_catcher *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_catchstack_ptr, (void *) thr, sizeof(duk_catcher) * new_size);
57510 if (!new_ptr) {
57511 /* No need for a NULL/zero-size check because new_size > 0) */
57512 DUK_ERROR_ALLOC_FAILED(thr);
57513 }
57514 thr->catchstack = new_ptr;
57515 thr->catchstack_size = new_size;
57516
57517 /* note: any entries above the catchstack top are garbage and not zeroed */
57518}
57519
57520DUK_INTERNAL void duk_hthread_catchstack_shrink_check(duk_hthread *thr) {
57521 duk_size_t new_size;
57522 duk_catcher *p;
57523
57524 DUK_ASSERT(thr != NULL);
57525 DUK_ASSERT_DISABLE(thr->catchstack_top >= 0); /* avoid warning (unsigned) */
57526 DUK_ASSERT(thr->catchstack_size >= thr->catchstack_top);
57527
57528 if (thr->catchstack_size - thr->catchstack_top < DUK_CATCHSTACK_SHRINK_THRESHOLD) {
57529 return;
57530 }
57531
57532 new_size = thr->catchstack_top + DUK_CATCHSTACK_SHRINK_SPARE;
57533 DUK_ASSERT(new_size >= thr->catchstack_top);
57534
57535 DUK_DD(DUK_DDPRINT("shrinking catchstack %ld -> %ld", (long) thr->catchstack_size, (long) new_size));
57536
57537 /*
57538 * Note: must use indirect variant of DUK_REALLOC() because underlying
57539 * pointer may be changed by mark-and-sweep.
57540 */
57541
57542 /* shrink failure is not fatal */
57543 p = (duk_catcher *) DUK_REALLOC_INDIRECT(thr->heap, duk_hthread_get_catchstack_ptr, (void *) thr, sizeof(duk_catcher) * new_size);
57544 if (p) {
57545 thr->catchstack = p;
57546 thr->catchstack_size = new_size;
57547 } else {
57548 /* Because new_size != 0, if condition doesn't need to be
57549 * (p != NULL || new_size == 0).
57550 */
57551 DUK_ASSERT(new_size != 0);
57552 DUK_D(DUK_DPRINT("catchstack shrink failed, ignoring"));
57553 }
57554
57555 /* note: any entries above the catchstack top are garbage and not zeroed */
57556}
57557
57558DUK_INTERNAL void duk_hthread_catchstack_unwind(duk_hthread *thr, duk_size_t new_top) {
57559 duk_size_t idx;
57560
57561 DUK_DDD(DUK_DDDPRINT("unwind catchstack top of thread %p from %ld to %ld",
57562 (void *) thr,
57563 (thr != NULL ? (long) thr->catchstack_top : (long) -1),
57564 (long) new_top));
57565
57566 DUK_ASSERT(thr);
57567 DUK_ASSERT(thr->heap);
57568 DUK_ASSERT_DISABLE(new_top >= 0); /* unsigned */
57569 DUK_ASSERT((duk_size_t) new_top <= thr->catchstack_top); /* cannot grow */
57570
57571 /*
57572 * Since there are no references in the catcher structure,
57573 * unwinding is quite simple. The only thing we need to
57574 * look out for is popping a possible lexical environment
57575 * established for an active catch clause.
57576 */
57577
57578 idx = thr->catchstack_top;
57579 while (idx > new_top) {
57580 duk_catcher *p;
57581 duk_activation *act;
57582 duk_hobject *env;
57583
57584 idx--;
57585 DUK_ASSERT_DISABLE(idx >= 0); /* unsigned */
57586 DUK_ASSERT((duk_size_t) idx < thr->catchstack_size);
57587
57588 p = thr->catchstack + idx;
57589
57590 if (DUK_CAT_HAS_LEXENV_ACTIVE(p)) {
57591 DUK_DDD(DUK_DDDPRINT("unwinding catchstack idx %ld, callstack idx %ld, callstack top %ld: lexical environment active",
57592 (long) idx, (long) p->callstack_index, (long) thr->callstack_top));
57593
57594 /* XXX: Here we have a nasty dependency: the need to manipulate
57595 * the callstack means that catchstack must always be unwound by
57596 * the caller before unwinding the callstack. This should be fixed
57597 * later.
57598 */
57599
57600 /* Note that multiple catchstack entries may refer to the same
57601 * callstack entry.
57602 */
57603 act = thr->callstack + p->callstack_index;
57604 DUK_ASSERT(act >= thr->callstack);
57605 DUK_ASSERT(act < thr->callstack + thr->callstack_top);
57606
57607 DUK_DDD(DUK_DDDPRINT("catchstack_index=%ld, callstack_index=%ld, lex_env=%!iO",
57608 (long) idx, (long) p->callstack_index,
57609 (duk_heaphdr *) act->lex_env));
57610
57611 env = act->lex_env; /* current lex_env of the activation (created for catcher) */
57612 DUK_ASSERT(env != NULL); /* must be, since env was created when catcher was created */
57613 act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env); /* prototype is lex_env before catcher created */
57614 DUK_HOBJECT_DECREF(thr, env);
57615
57616 /* There is no need to decref anything else than 'env': if 'env'
57617 * becomes unreachable, refzero will handle decref'ing its prototype.
57618 */
57619 }
57620 }
57621
57622 thr->catchstack_top = new_top;
57623
57624 /* note: any entries above the catchstack top are garbage and not zeroed */
57625}
57626/*
57627 * Shared helpers for arithmetic operations
57628 */
57629
57630/* #include duk_internal.h -> already included */
57631
57632/* Ecmascript modulus ('%') does not match IEEE 754 "remainder" operation
57633 * (implemented by remainder() in C99) but does seem to match ANSI C fmod().
57634 * Compare E5 Section 11.5.3 and "man fmod".
57635 */
57636DUK_INTERNAL double duk_js_arith_mod(double d1, double d2) {
57637#if defined(DUK_USE_POW_WORKAROUNDS)
57638 /* Specific fixes to common fmod() implementation issues:
57639 * - test-bug-mingw-math-issues.js
57640 */
57641 if (DUK_ISINF(d2)) {
57642 if (DUK_ISINF(d1)) {
57643 return DUK_DOUBLE_NAN;
57644 } else {
57645 return d1;
57646 }
57647 } else if (d1 == 0.0) {
57648 /* d1 +/-0 is returned as is (preserving sign) except when
57649 * d2 is zero or NaN.
57650 */
57651 if (d2 == 0.0 || DUK_ISNAN(d2)) {
57652 return DUK_DOUBLE_NAN;
57653 } else {
57654 return d1;
57655 }
57656 }
57657#else
57658 /* Some ISO C assumptions. */
57659 DUK_ASSERT(DUK_FMOD(1.0, DUK_DOUBLE_INFINITY) == 1.0);
57660 DUK_ASSERT(DUK_FMOD(-1.0, DUK_DOUBLE_INFINITY) == -1.0);
57661 DUK_ASSERT(DUK_FMOD(1.0, -DUK_DOUBLE_INFINITY) == 1.0);
57662 DUK_ASSERT(DUK_FMOD(-1.0, -DUK_DOUBLE_INFINITY) == -1.0);
57663 DUK_ASSERT(DUK_ISNAN(DUK_FMOD(DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY)));
57664 DUK_ASSERT(DUK_ISNAN(DUK_FMOD(DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY)));
57665 DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-DUK_DOUBLE_INFINITY, DUK_DOUBLE_INFINITY)));
57666 DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-DUK_DOUBLE_INFINITY, -DUK_DOUBLE_INFINITY)));
57667 DUK_ASSERT(DUK_FMOD(0.0, 1.0) == 0.0 && DUK_SIGNBIT(DUK_FMOD(0.0, 1.0)) == 0);
57668 DUK_ASSERT(DUK_FMOD(-0.0, 1.0) == 0.0 && DUK_SIGNBIT(DUK_FMOD(-0.0, 1.0)) != 0);
57669 DUK_ASSERT(DUK_FMOD(0.0, DUK_DOUBLE_INFINITY) == 0.0 && DUK_SIGNBIT(DUK_FMOD(0.0, DUK_DOUBLE_INFINITY)) == 0);
57670 DUK_ASSERT(DUK_FMOD(-0.0, DUK_DOUBLE_INFINITY) == 0.0 && DUK_SIGNBIT(DUK_FMOD(-0.0, DUK_DOUBLE_INFINITY)) != 0);
57671 DUK_ASSERT(DUK_FMOD(0.0, -DUK_DOUBLE_INFINITY) == 0.0 && DUK_SIGNBIT(DUK_FMOD(0.0, DUK_DOUBLE_INFINITY)) == 0);
57672 DUK_ASSERT(DUK_FMOD(-0.0, -DUK_DOUBLE_INFINITY) == 0.0 && DUK_SIGNBIT(DUK_FMOD(-0.0, -DUK_DOUBLE_INFINITY)) != 0);
57673 DUK_ASSERT(DUK_ISNAN(DUK_FMOD(0.0, 0.0)));
57674 DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-0.0, 0.0)));
57675 DUK_ASSERT(DUK_ISNAN(DUK_FMOD(0.0, -0.0)));
57676 DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-0.0, -0.0)));
57677 DUK_ASSERT(DUK_ISNAN(DUK_FMOD(0.0, DUK_DOUBLE_NAN)));
57678 DUK_ASSERT(DUK_ISNAN(DUK_FMOD(-0.0, DUK_DOUBLE_NAN)));
57679#endif
57680
57681 return (duk_double_t) DUK_FMOD((double) d1, (double) d2);
57682}
57683
57684/* Shared helper for Math.pow() and exponentiation operator. */
57685DUK_INTERNAL double duk_js_arith_pow(double x, double y) {
57686 /* The ANSI C pow() semantics differ from Ecmascript.
57687 *
57688 * E.g. when x==1 and y is +/- infinite, the Ecmascript required
57689 * result is NaN, while at least Linux pow() returns 1.
57690 */
57691
57692 duk_small_int_t cx, cy, sx;
57693
57694 DUK_UNREF(cx);
57695 DUK_UNREF(sx);
57696 cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
57697
57698 if (cy == DUK_FP_NAN) {
57699 goto ret_nan;
57700 }
57701 if (DUK_FABS(x) == 1.0 && cy == DUK_FP_INFINITE) {
57702 goto ret_nan;
57703 }
57704
57705#if defined(DUK_USE_POW_WORKAROUNDS)
57706 /* Specific fixes to common pow() implementation issues:
57707 * - test-bug-netbsd-math-pow.js: NetBSD 6.0 on x86 (at least)
57708 * - test-bug-mingw-math-issues.js
57709 */
57710 cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
57711 if (cx == DUK_FP_ZERO && y < 0.0) {
57712 sx = (duk_small_int_t) DUK_SIGNBIT(x);
57713 if (sx == 0) {
57714 /* Math.pow(+0,y) should be Infinity when y<0. NetBSD pow()
57715 * returns -Infinity instead when y is <0 and finite. The
57716 * if-clause also catches y == -Infinity (which works even
57717 * without the fix).
57718 */
57719 return DUK_DOUBLE_INFINITY;
57720 } else {
57721 /* Math.pow(-0,y) where y<0 should be:
57722 * - -Infinity if y<0 and an odd integer
57723 * - Infinity if y<0 but not an odd integer
57724 * NetBSD pow() returns -Infinity for all finite y<0. The
57725 * if-clause also catches y == -Infinity (which works even
57726 * without the fix).
57727 */
57728
57729 /* fmod() return value has same sign as input (negative) so
57730 * the result here will be in the range ]-2,0], -1 indicates
57731 * odd. If x is -Infinity, NaN is returned and the odd check
57732 * always concludes "not odd" which results in desired outcome.
57733 */
57734 double tmp = DUK_FMOD(y, 2);
57735 if (tmp == -1.0) {
57736 return -DUK_DOUBLE_INFINITY;
57737 } else {
57738 /* Not odd, or y == -Infinity */
57739 return DUK_DOUBLE_INFINITY;
57740 }
57741 }
57742 } else if (cx == DUK_FP_NAN) {
57743 if (y == 0.0) {
57744 /* NaN ** +/- 0 should always be 1, but is NaN on
57745 * at least some Cygwin/MinGW versions.
57746 */
57747 return 1.0;
57748 }
57749 }
57750#else
57751 /* Some ISO C assumptions. */
57752 DUK_ASSERT(DUK_POW(DUK_DOUBLE_NAN, 0.0) == 1.0);
57753 DUK_ASSERT(DUK_ISINF(DUK_POW(0.0, -1.0)) && DUK_SIGNBIT(DUK_POW(0.0, -1.0)) == 0);
57754 DUK_ASSERT(DUK_ISINF(DUK_POW(-0.0, -2.0)) && DUK_SIGNBIT(DUK_POW(-0.0, -2.0)) == 0);
57755 DUK_ASSERT(DUK_ISINF(DUK_POW(-0.0, -3.0)) && DUK_SIGNBIT(DUK_POW(-0.0, -3.0)) != 0);
57756#endif
57757
57758 return DUK_POW(x, y);
57759
57760 ret_nan:
57761 return DUK_DOUBLE_NAN;
57762}
57763/*
57764 * Call handling.
57765 *
57766 * Main functions are:
57767 *
57768 * - duk_handle_call_unprotected(): unprotected call to Ecmascript or
57769 * Duktape/C function
57770 * - duk_handle_call_protected(): protected call to Ecmascript or
57771 * Duktape/C function
57772 * - duk_handle_safe_call(): make a protected C call within current
57773 * activation
57774 * - duk_handle_ecma_call_setup(): Ecmascript-to-Ecmascript calls
57775 * (not always possible), including tail calls and coroutine resume
57776 *
57777 * See 'execution.rst'.
57778 *
57779 * Note: setjmp() and local variables have a nasty interaction,
57780 * see execution.rst; non-volatile locals modified after setjmp()
57781 * call are not guaranteed to keep their value.
57782 */
57783
57784/* #include duk_internal.h -> already included */
57785
57786/*
57787 * Forward declarations.
57788 */
57789
57790DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr,
57791 duk_idx_t num_stack_args,
57792 duk_small_uint_t call_flags,
57793 duk_idx_t idx_func);
57794DUK_LOCAL void duk__handle_call_error(duk_hthread *thr,
57795 duk_size_t entry_valstack_bottom_index,
57796 duk_size_t entry_valstack_end,
57797 duk_size_t entry_catchstack_top,
57798 duk_size_t entry_callstack_top,
57799 duk_int_t entry_call_recursion_depth,
57800 duk_hthread *entry_curr_thread,
57801 duk_uint_fast8_t entry_thread_state,
57802 duk_instr_t **entry_ptr_curr_pc,
57803 duk_idx_t idx_func,
57804 duk_jmpbuf *old_jmpbuf_ptr);
57805DUK_LOCAL void duk__handle_safe_call_inner(duk_hthread *thr,
57806 duk_safe_call_function func,
57807 void *udata,
57808 duk_idx_t idx_retbase,
57809 duk_idx_t num_stack_rets,
57810 duk_size_t entry_valstack_bottom_index,
57811 duk_size_t entry_callstack_top,
57812 duk_size_t entry_catchstack_top);
57813DUK_LOCAL void duk__handle_safe_call_error(duk_hthread *thr,
57814 duk_idx_t idx_retbase,
57815 duk_idx_t num_stack_rets,
57816 duk_size_t entry_valstack_bottom_index,
57817 duk_size_t entry_callstack_top,
57818 duk_size_t entry_catchstack_top,
57819 duk_jmpbuf *old_jmpbuf_ptr);
57820DUK_LOCAL void duk__handle_safe_call_shared(duk_hthread *thr,
57821 duk_idx_t idx_retbase,
57822 duk_idx_t num_stack_rets,
57823 duk_int_t entry_call_recursion_depth,
57824 duk_hthread *entry_curr_thread,
57825 duk_uint_fast8_t entry_thread_state,
57826 duk_instr_t **entry_ptr_curr_pc);
57827
57828/*
57829 * Interrupt counter fixup (for development only).
57830 */
57831
57832#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
57833DUK_LOCAL void duk__interrupt_fixup(duk_hthread *thr, duk_hthread *entry_curr_thread) {
57834 /* Currently the bytecode executor and executor interrupt
57835 * instruction counts are off because we don't execute the
57836 * interrupt handler when we're about to exit from the initial
57837 * user call into Duktape.
57838 *
57839 * If we were to execute the interrupt handler here, the counts
57840 * would match. You can enable this block manually to check
57841 * that this is the case.
57842 */
57843
57844 DUK_ASSERT(thr != NULL);
57845 DUK_ASSERT(thr->heap != NULL);
57846
57847#if defined(DUK_USE_INTERRUPT_DEBUG_FIXUP)
57848 if (entry_curr_thread == NULL) {
57849 thr->interrupt_init = thr->interrupt_init - thr->interrupt_counter;
57850 thr->heap->inst_count_interrupt += thr->interrupt_init;
57851 DUK_DD(DUK_DDPRINT("debug test: updated interrupt count on exit to "
57852 "user code, instruction counts: executor=%ld, interrupt=%ld",
57853 (long) thr->heap->inst_count_exec, (long) thr->heap->inst_count_interrupt));
57854 DUK_ASSERT(thr->heap->inst_count_exec == thr->heap->inst_count_interrupt);
57855 }
57856#else
57857 DUK_UNREF(thr);
57858 DUK_UNREF(entry_curr_thread);
57859#endif
57860}
57861#endif
57862
57863/*
57864 * Arguments object creation.
57865 *
57866 * Creating arguments objects involves many small details, see E5 Section
57867 * 10.6 for the specific requirements. Much of the arguments object exotic
57868 * behavior is implemented in duk_hobject_props.c, and is enabled by the
57869 * object flag DUK_HOBJECT_FLAG_EXOTIC_ARGUMENTS.
57870 */
57871
57872DUK_LOCAL void duk__create_arguments_object(duk_hthread *thr,
57873 duk_hobject *func,
57874 duk_hobject *varenv,
57875 duk_idx_t idx_argbase, /* idx of first argument on stack */
57876 duk_idx_t num_stack_args) { /* num args starting from idx_argbase */
57877 duk_context *ctx = (duk_context *) thr;
57878 duk_hobject *arg; /* 'arguments' */
57879 duk_hobject *formals; /* formals for 'func' (may be NULL if func is a C function) */
57880 duk_idx_t i_arg;
57881 duk_idx_t i_map;
57882 duk_idx_t i_mappednames;
57883 duk_idx_t i_formals;
57884 duk_idx_t i_argbase;
57885 duk_idx_t n_formals;
57886 duk_idx_t idx;
57887 duk_bool_t need_map;
57888
57889 DUK_DDD(DUK_DDDPRINT("creating arguments object for func=%!iO, varenv=%!iO, "
57890 "idx_argbase=%ld, num_stack_args=%ld",
57891 (duk_heaphdr *) func, (duk_heaphdr *) varenv,
57892 (long) idx_argbase, (long) num_stack_args));
57893
57894 DUK_ASSERT(thr != NULL);
57895 DUK_ASSERT(func != NULL);
57896 DUK_ASSERT(DUK_HOBJECT_IS_NONBOUND_FUNCTION(func));
57897 DUK_ASSERT(varenv != NULL);
57898 DUK_ASSERT(idx_argbase >= 0); /* assumed to bottom relative */
57899 DUK_ASSERT(num_stack_args >= 0);
57900
57901 need_map = 0;
57902
57903 i_argbase = idx_argbase;
57904 DUK_ASSERT(i_argbase >= 0);
57905
57906 duk_push_hobject(ctx, func);
57907 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_FORMALS);
57908 formals = duk_get_hobject(ctx, -1);
57909 if (formals) {
57910 n_formals = (duk_idx_t) duk_get_length(ctx, -1);
57911 } else {
57912 /* This shouldn't happen without tampering of internal
57913 * properties: if a function accesses 'arguments', _Formals
57914 * is kept. Check for the case anyway in case internal
57915 * properties have been modified manually.
57916 */
57917 DUK_D(DUK_DPRINT("_Formals is undefined when creating arguments, use n_formals == 0"));
57918 n_formals = 0;
57919 }
57920 duk_remove_m2(ctx); /* leave formals on stack for later use */
57921 i_formals = duk_require_top_index(ctx);
57922
57923 DUK_ASSERT(n_formals >= 0);
57924 DUK_ASSERT(formals != NULL || n_formals == 0);
57925
57926 DUK_DDD(DUK_DDDPRINT("func=%!O, formals=%!O, n_formals=%ld",
57927 (duk_heaphdr *) func, (duk_heaphdr *) formals,
57928 (long) n_formals));
57929
57930 /* [ ... formals ] */
57931
57932 /*
57933 * Create required objects:
57934 * - 'arguments' object: array-like, but not an array
57935 * - 'map' object: internal object, tied to 'arguments'
57936 * - 'mappedNames' object: temporary value used during construction
57937 */
57938
57939 arg = duk_push_object_helper(ctx,
57940 DUK_HOBJECT_FLAG_EXTENSIBLE |
57941 DUK_HOBJECT_FLAG_ARRAY_PART |
57942 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_ARGUMENTS),
57943 DUK_BIDX_OBJECT_PROTOTYPE);
57944 DUK_ASSERT(arg != NULL);
57945 (void) duk_push_object_helper(ctx,
57946 DUK_HOBJECT_FLAG_EXTENSIBLE |
57947 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
57948 -1); /* no prototype */
57949 (void) duk_push_object_helper(ctx,
57950 DUK_HOBJECT_FLAG_EXTENSIBLE |
57951 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJECT),
57952 -1); /* no prototype */
57953 i_arg = duk_get_top(ctx) - 3;
57954 i_map = i_arg + 1;
57955 i_mappednames = i_arg + 2;
57956
57957 /* [ ... formals arguments map mappedNames ] */
57958
57959 DUK_DDD(DUK_DDDPRINT("created arguments related objects: "
57960 "arguments at index %ld -> %!O "
57961 "map at index %ld -> %!O "
57962 "mappednames at index %ld -> %!O",
57963 (long) i_arg, (duk_heaphdr *) duk_get_hobject(ctx, i_arg),
57964 (long) i_map, (duk_heaphdr *) duk_get_hobject(ctx, i_map),
57965 (long) i_mappednames, (duk_heaphdr *) duk_get_hobject(ctx, i_mappednames)));
57966
57967 /*
57968 * Init arguments properties, map, etc.
57969 */
57970
57971 duk_push_int(ctx, num_stack_args);
57972 duk_xdef_prop_stridx(ctx, i_arg, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_WC);
57973
57974 /*
57975 * Init argument related properties
57976 */
57977
57978 /* step 11 */
57979 idx = num_stack_args - 1;
57980 while (idx >= 0) {
57981 DUK_DDD(DUK_DDDPRINT("arg idx %ld, argbase=%ld, argidx=%ld",
57982 (long) idx, (long) i_argbase, (long) (i_argbase + idx)));
57983
57984 DUK_DDD(DUK_DDDPRINT("define arguments[%ld]=arg", (long) idx));
57985 duk_dup(ctx, i_argbase + idx);
57986 duk_xdef_prop_index_wec(ctx, i_arg, (duk_uarridx_t) idx);
57987 DUK_DDD(DUK_DDDPRINT("defined arguments[%ld]=arg", (long) idx));
57988
57989 /* step 11.c is relevant only if non-strict (checked in 11.c.ii) */
57990 if (!DUK_HOBJECT_HAS_STRICT(func) && idx < n_formals) {
57991 DUK_ASSERT(formals != NULL);
57992
57993 DUK_DDD(DUK_DDDPRINT("strict function, index within formals (%ld < %ld)",
57994 (long) idx, (long) n_formals));
57995
57996 duk_get_prop_index(ctx, i_formals, idx);
57997 DUK_ASSERT(duk_is_string(ctx, -1));
57998
57999 duk_dup_top(ctx); /* [ ... name name ] */
58000
58001 if (!duk_has_prop(ctx, i_mappednames)) {
58002 /* steps 11.c.ii.1 - 11.c.ii.4, but our internal book-keeping
58003 * differs from the reference model
58004 */
58005
58006 /* [ ... name ] */
58007
58008 need_map = 1;
58009
58010 DUK_DDD(DUK_DDDPRINT("set mappednames[%s]=%ld",
58011 (const char *) duk_get_string(ctx, -1),
58012 (long) idx));
58013 duk_dup_top(ctx); /* name */
58014 (void) duk_push_uint_to_hstring(ctx, (duk_uint_t) idx); /* index */
58015 duk_xdef_prop_wec(ctx, i_mappednames); /* out of spec, must be configurable */
58016
58017 DUK_DDD(DUK_DDDPRINT("set map[%ld]=%s",
58018 (long) idx,
58019 duk_get_string(ctx, -1)));
58020 duk_dup_top(ctx); /* name */
58021 duk_xdef_prop_index_wec(ctx, i_map, (duk_uarridx_t) idx); /* out of spec, must be configurable */
58022 } else {
58023 /* duk_has_prop() popped the second 'name' */
58024 }
58025
58026 /* [ ... name ] */
58027 duk_pop(ctx); /* pop 'name' */
58028 }
58029
58030 idx--;
58031 }
58032
58033 DUK_DDD(DUK_DDDPRINT("actual arguments processed"));
58034
58035 /* step 12 */
58036 if (need_map) {
58037 DUK_DDD(DUK_DDDPRINT("adding 'map' and 'varenv' to arguments object"));
58038
58039 /* should never happen for a strict callee */
58040 DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(func));
58041
58042 duk_dup(ctx, i_map);
58043 duk_xdef_prop_stridx(ctx, i_arg, DUK_STRIDX_INT_MAP, DUK_PROPDESC_FLAGS_NONE); /* out of spec, don't care */
58044
58045 /* The variable environment for magic variable bindings needs to be
58046 * given by the caller and recorded in the arguments object.
58047 *
58048 * See E5 Section 10.6, the creation of setters/getters.
58049 *
58050 * The variable environment also provides access to the callee, so
58051 * an explicit (internal) callee property is not needed.
58052 */
58053
58054 duk_push_hobject(ctx, varenv);
58055 duk_xdef_prop_stridx(ctx, i_arg, DUK_STRIDX_INT_VARENV, DUK_PROPDESC_FLAGS_NONE); /* out of spec, don't care */
58056 }
58057
58058 /* steps 13-14 */
58059 if (DUK_HOBJECT_HAS_STRICT(func)) {
58060 /* Callee/caller are throwers and are not deletable etc. They
58061 * could be implemented as virtual properties, but currently
58062 * there is no support for virtual properties which are accessors
58063 * (only plain virtual properties). This would not be difficult
58064 * to change in duk_hobject_props, but we can make the throwers
58065 * normal, concrete properties just as easily.
58066 *
58067 * Note that the specification requires that the *same* thrower
58068 * built-in object is used here! See E5 Section 10.6 main
58069 * algoritm, step 14, and Section 13.2.3 which describes the
58070 * thrower. See test case test-arguments-throwers.js.
58071 */
58072
58073 DUK_DDD(DUK_DDDPRINT("strict function, setting caller/callee to throwers"));
58074
58075 duk_xdef_prop_stridx_thrower(ctx, i_arg, DUK_STRIDX_CALLER);
58076 duk_xdef_prop_stridx_thrower(ctx, i_arg, DUK_STRIDX_CALLEE);
58077 } else {
58078 DUK_DDD(DUK_DDDPRINT("non-strict function, setting callee to actual value"));
58079 duk_push_hobject(ctx, func);
58080 duk_xdef_prop_stridx(ctx, i_arg, DUK_STRIDX_CALLEE, DUK_PROPDESC_FLAGS_WC);
58081 }
58082
58083 /* set exotic behavior only after we're done */
58084 if (need_map) {
58085 /* Exotic behaviors are only enabled for arguments objects
58086 * which have a parameter map (see E5 Section 10.6 main
58087 * algorithm, step 12).
58088 *
58089 * In particular, a non-strict arguments object with no
58090 * mapped formals does *NOT* get exotic behavior, even
58091 * for e.g. "caller" property. This seems counterintuitive
58092 * but seems to be the case.
58093 */
58094
58095 /* cannot be strict (never mapped variables) */
58096 DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(func));
58097
58098 DUK_DDD(DUK_DDDPRINT("enabling exotic behavior for arguments object"));
58099 DUK_HOBJECT_SET_EXOTIC_ARGUMENTS(arg);
58100 } else {
58101 DUK_DDD(DUK_DDDPRINT("not enabling exotic behavior for arguments object"));
58102 }
58103
58104 DUK_DDD(DUK_DDDPRINT("final arguments related objects: "
58105 "arguments at index %ld -> %!O "
58106 "map at index %ld -> %!O "
58107 "mappednames at index %ld -> %!O",
58108 (long) i_arg, (duk_heaphdr *) duk_get_hobject(ctx, i_arg),
58109 (long) i_map, (duk_heaphdr *) duk_get_hobject(ctx, i_map),
58110 (long) i_mappednames, (duk_heaphdr *) duk_get_hobject(ctx, i_mappednames)));
58111
58112 /* [ args(n) [crud] formals arguments map mappednames ] */
58113
58114 duk_pop_2(ctx);
58115 duk_remove_m2(ctx);
58116
58117 /* [ args [crud] arguments ] */
58118}
58119
58120/* Helper for creating the arguments object and adding it to the env record
58121 * on top of the value stack. This helper has a very strict dependency on
58122 * the shape of the input stack.
58123 */
58124DUK_LOCAL void duk__handle_createargs_for_call(duk_hthread *thr,
58125 duk_hobject *func,
58126 duk_hobject *env,
58127 duk_idx_t num_stack_args) {
58128 duk_context *ctx = (duk_context *) thr;
58129
58130 DUK_DDD(DUK_DDDPRINT("creating arguments object for function call"));
58131
58132 DUK_ASSERT(thr != NULL);
58133 DUK_ASSERT(func != NULL);
58134 DUK_ASSERT(env != NULL);
58135 DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
58136 DUK_ASSERT(duk_get_top(ctx) >= num_stack_args + 1);
58137
58138 /* [ ... arg1 ... argN envobj ] */
58139
58140 duk__create_arguments_object(thr,
58141 func,
58142 env,
58143 duk_get_top(ctx) - num_stack_args - 1, /* idx_argbase */
58144 num_stack_args);
58145
58146 /* [ ... arg1 ... argN envobj argobj ] */
58147
58148 duk_xdef_prop_stridx_short(ctx,
58149 -2,
58150 DUK_STRIDX_LC_ARGUMENTS,
58151 DUK_HOBJECT_HAS_STRICT(func) ? DUK_PROPDESC_FLAGS_E : /* strict: non-deletable, non-writable */
58152 DUK_PROPDESC_FLAGS_WE); /* non-strict: non-deletable, writable */
58153 /* [ ... arg1 ... argN envobj ] */
58154}
58155
58156/*
58157 * Helper for handling a "bound function" chain when a call is being made.
58158 *
58159 * Follows the bound function chain until a non-bound function is found.
58160 * Prepends the bound arguments to the value stack (at idx_func + 2),
58161 * updating 'num_stack_args' in the process. The 'this' binding is also
58162 * updated if necessary (at idx_func + 1). Note that for constructor calls
58163 * the 'this' binding is never updated by [[BoundThis]].
58164 *
58165 * XXX: bound function chains could be collapsed at bound function creation
58166 * time so that each bound function would point directly to a non-bound
58167 * function. This would make call time handling much easier.
58168 */
58169
58170DUK_LOCAL void duk__handle_bound_chain_for_call(duk_hthread *thr,
58171 duk_idx_t idx_func,
58172 duk_idx_t *p_num_stack_args, /* may be changed by call */
58173 duk_bool_t is_constructor_call) {
58174 duk_context *ctx = (duk_context *) thr;
58175 duk_idx_t num_stack_args;
58176 duk_tval *tv_func;
58177 duk_hobject *func;
58178 duk_uint_t sanity;
58179
58180 DUK_ASSERT(thr != NULL);
58181 DUK_ASSERT(p_num_stack_args != NULL);
58182
58183 /* On entry, item at idx_func is a bound, non-lightweight function,
58184 * but we don't rely on that below.
58185 */
58186
58187 num_stack_args = *p_num_stack_args;
58188
58189 sanity = DUK_HOBJECT_BOUND_CHAIN_SANITY;
58190 do {
58191 duk_idx_t i, len;
58192
58193 tv_func = duk_require_tval(ctx, idx_func);
58194 DUK_ASSERT(tv_func != NULL);
58195
58196 if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) {
58197 /* Lightweight function: never bound, so terminate. */
58198 break;
58199 } else if (DUK_TVAL_IS_OBJECT(tv_func)) {
58200 func = DUK_TVAL_GET_OBJECT(tv_func);
58201 if (!DUK_HOBJECT_HAS_BOUNDFUNC(func)) {
58202 /* Normal non-bound function. */
58203 break;
58204 }
58205 } else {
58206 /* Function.prototype.bind() should never let this happen,
58207 * ugly error message is enough.
58208 */
58209 DUK_ERROR_INTERNAL(thr);
58210 }
58211 DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv_func) != NULL);
58212
58213 /* XXX: this could be more compact by accessing the internal properties
58214 * directly as own properties (they cannot be inherited, and are not
58215 * externally visible).
58216 */
58217
58218 DUK_DDD(DUK_DDDPRINT("bound function encountered, ptr=%p, num_stack_args=%ld: %!T",
58219 (void *) DUK_TVAL_GET_OBJECT(tv_func), (long) num_stack_args, tv_func));
58220
58221 /* [ ... func this arg1 ... argN ] */
58222
58223 if (is_constructor_call) {
58224 /* See: tests/ecmascript/test-spec-bound-constructor.js */
58225 DUK_DDD(DUK_DDDPRINT("constructor call: don't update this binding"));
58226 } else {
58227 duk_get_prop_stridx(ctx, idx_func, DUK_STRIDX_INT_THIS);
58228 duk_replace(ctx, idx_func + 1); /* idx_this = idx_func + 1 */
58229 }
58230
58231 /* [ ... func this arg1 ... argN ] */
58232
58233 /* XXX: duk_get_length? */
58234 duk_get_prop_stridx(ctx, idx_func, DUK_STRIDX_INT_ARGS); /* -> [ ... func this arg1 ... argN _Args ] */
58235 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_LENGTH); /* -> [ ... func this arg1 ... argN _Args length ] */
58236 len = (duk_idx_t) duk_require_int(ctx, -1);
58237 duk_pop(ctx);
58238 for (i = 0; i < len; i++) {
58239 /* XXX: very slow - better to bulk allocate a gap, and copy
58240 * from args_array directly (we know it has a compact array
58241 * part, etc).
58242 */
58243
58244 /* [ ... func this <some bound args> arg1 ... argN _Args ] */
58245 duk_get_prop_index(ctx, -1, i);
58246 duk_insert(ctx, idx_func + 2 + i); /* idx_args = idx_func + 2 */
58247 }
58248 num_stack_args += len; /* must be updated to work properly (e.g. creation of 'arguments') */
58249 duk_pop(ctx);
58250
58251 /* [ ... func this <bound args> arg1 ... argN ] */
58252
58253 duk_get_prop_stridx(ctx, idx_func, DUK_STRIDX_INT_TARGET);
58254 duk_replace(ctx, idx_func); /* replace in stack */
58255
58256 DUK_DDD(DUK_DDDPRINT("bound function handled, num_stack_args=%ld, idx_func=%ld, curr func=%!T",
58257 (long) num_stack_args, (long) idx_func, duk_get_tval(ctx, idx_func)));
58258 } while (--sanity > 0);
58259
58260 if (sanity == 0) {
58261 DUK_ERROR_RANGE(thr, DUK_STR_BOUND_CHAIN_LIMIT);
58262 }
58263
58264 DUK_DDD(DUK_DDDPRINT("final non-bound function is: %!T", duk_get_tval(ctx, idx_func)));
58265
58266#if defined(DUK_USE_ASSERTIONS)
58267 tv_func = duk_require_tval(ctx, idx_func);
58268 DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func) || DUK_TVAL_IS_OBJECT(tv_func));
58269 if (DUK_TVAL_IS_OBJECT(tv_func)) {
58270 func = DUK_TVAL_GET_OBJECT(tv_func);
58271 DUK_ASSERT(func != NULL);
58272 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func));
58273 DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func) ||
58274 DUK_HOBJECT_HAS_NATFUNC(func));
58275 }
58276#endif
58277
58278 /* write back */
58279 *p_num_stack_args = num_stack_args;
58280}
58281
58282/*
58283 * Helper for setting up var_env and lex_env of an activation,
58284 * assuming it does NOT have the DUK_HOBJECT_FLAG_NEWENV flag.
58285 */
58286
58287DUK_LOCAL void duk__handle_oldenv_for_call(duk_hthread *thr,
58288 duk_hobject *func,
58289 duk_activation *act) {
58290 duk_hcompfunc *f;
58291 duk_hobject *h_lex;
58292 duk_hobject *h_var;
58293
58294 DUK_ASSERT(thr != NULL);
58295 DUK_ASSERT(func != NULL);
58296 DUK_ASSERT(act != NULL);
58297 DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV(func));
58298 DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func));
58299 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(func));
58300 DUK_UNREF(thr);
58301
58302 f = (duk_hcompfunc *) func;
58303 h_lex = DUK_HCOMPFUNC_GET_LEXENV(thr->heap, f);
58304 h_var = DUK_HCOMPFUNC_GET_VARENV(thr->heap, f);
58305 DUK_ASSERT(h_lex != NULL); /* Always true for closures (not for templates) */
58306 DUK_ASSERT(h_var != NULL);
58307 act->lex_env = h_lex;
58308 act->var_env = h_var;
58309 DUK_HOBJECT_INCREF(thr, h_lex);
58310 DUK_HOBJECT_INCREF(thr, h_var);
58311}
58312
58313/*
58314 * Helper for updating callee 'caller' property.
58315 */
58316
58317#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
58318DUK_LOCAL void duk__update_func_caller_prop(duk_hthread *thr, duk_hobject *func) {
58319 duk_tval *tv_caller;
58320 duk_hobject *h_tmp;
58321 duk_activation *act_callee;
58322 duk_activation *act_caller;
58323
58324 DUK_ASSERT(thr != NULL);
58325 DUK_ASSERT(func != NULL);
58326 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func)); /* bound chain resolved */
58327 DUK_ASSERT(thr->callstack_top >= 1);
58328
58329 if (DUK_HOBJECT_HAS_STRICT(func)) {
58330 /* Strict functions don't get their 'caller' updated. */
58331 return;
58332 }
58333
58334 act_callee = thr->callstack + thr->callstack_top - 1;
58335 act_caller = (thr->callstack_top >= 2 ? act_callee - 1 : NULL);
58336
58337 /* XXX: check .caller writability? */
58338
58339 /* Backup 'caller' property and update its value. */
58340 tv_caller = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_CALLER(thr));
58341 if (tv_caller) {
58342 /* If caller is global/eval code, 'caller' should be set to
58343 * 'null'.
58344 *
58345 * XXX: there is no exotic flag to infer this correctly now.
58346 * The NEWENV flag is used now which works as intended for
58347 * everything (global code, non-strict eval code, and functions)
58348 * except strict eval code. Bound functions are never an issue
58349 * because 'func' has been resolved to a non-bound function.
58350 */
58351
58352 if (act_caller) {
58353 /* act_caller->func may be NULL in some finalization cases,
58354 * just treat like we don't know the caller.
58355 */
58356 if (act_caller->func && !DUK_HOBJECT_HAS_NEWENV(act_caller->func)) {
58357 /* Setting to NULL causes 'caller' to be set to
58358 * 'null' as desired.
58359 */
58360 act_caller = NULL;
58361 }
58362 }
58363
58364 if (DUK_TVAL_IS_OBJECT(tv_caller)) {
58365 h_tmp = DUK_TVAL_GET_OBJECT(tv_caller);
58366 DUK_ASSERT(h_tmp != NULL);
58367 act_callee->prev_caller = h_tmp;
58368
58369 /* Previous value doesn't need refcount changes because its ownership
58370 * is transferred to prev_caller.
58371 */
58372
58373 if (act_caller) {
58374 DUK_ASSERT(act_caller->func != NULL);
58375 DUK_TVAL_SET_OBJECT(tv_caller, act_caller->func);
58376 DUK_TVAL_INCREF(thr, tv_caller);
58377 } else {
58378 DUK_TVAL_SET_NULL(tv_caller); /* no incref */
58379 }
58380 } else {
58381 /* 'caller' must only take on 'null' or function value */
58382 DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_caller));
58383 DUK_ASSERT(act_callee->prev_caller == NULL);
58384 if (act_caller && act_caller->func) {
58385 /* Tolerate act_caller->func == NULL which happens in
58386 * some finalization cases; treat like unknown caller.
58387 */
58388 DUK_TVAL_SET_OBJECT(tv_caller, act_caller->func);
58389 DUK_TVAL_INCREF(thr, tv_caller);
58390 } else {
58391 DUK_TVAL_SET_NULL(tv_caller); /* no incref */
58392 }
58393 }
58394 }
58395}
58396#endif /* DUK_USE_NONSTD_FUNC_CALLER_PROPERTY */
58397
58398/*
58399 * Determine the effective 'this' binding and coerce the current value
58400 * on the valstack to the effective one (in-place, at idx_this).
58401 *
58402 * The current this value in the valstack (at idx_this) represents either:
58403 * - the caller's requested 'this' binding; or
58404 * - a 'this' binding accumulated from the bound function chain
58405 *
58406 * The final 'this' binding for the target function may still be
58407 * different, and is determined as described in E5 Section 10.4.3.
58408 *
58409 * For global and eval code (E5 Sections 10.4.1 and 10.4.2), we assume
58410 * that the caller has provided the correct 'this' binding explicitly
58411 * when calling, i.e.:
58412 *
58413 * - global code: this=global object
58414 * - direct eval: this=copy from eval() caller's this binding
58415 * - other eval: this=global object
58416 *
58417 * Note: this function may cause a recursive function call with arbitrary
58418 * side effects, because ToObject() may be called.
58419 */
58420
58421DUK_LOCAL void duk__coerce_effective_this_binding(duk_hthread *thr,
58422 duk_hobject *func,
58423 duk_idx_t idx_this) {
58424 duk_context *ctx = (duk_context *) thr;
58425 duk_tval *tv_this;
58426 duk_hobject *obj_global;
58427
58428 if (func == NULL || DUK_HOBJECT_HAS_STRICT(func)) {
58429 /* Lightfuncs are always considered strict. */
58430 DUK_DDD(DUK_DDDPRINT("this binding: strict -> use directly"));
58431 return;
58432 }
58433
58434 /* XXX: byte offset */
58435 tv_this = thr->valstack_bottom + idx_this;
58436 switch (DUK_TVAL_GET_TAG(tv_this)) {
58437 case DUK_TAG_OBJECT:
58438 DUK_DDD(DUK_DDDPRINT("this binding: non-strict, object -> use directly"));
58439 break;
58440 case DUK_TAG_UNDEFINED:
58441 case DUK_TAG_NULL:
58442 DUK_DDD(DUK_DDDPRINT("this binding: non-strict, undefined/null -> use global object"));
58443 obj_global = thr->builtins[DUK_BIDX_GLOBAL];
58444 /* XXX: avoid this check somehow */
58445 if (DUK_LIKELY(obj_global != NULL)) {
58446 DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_this)); /* no need to decref previous value */
58447 DUK_TVAL_SET_OBJECT(tv_this, obj_global);
58448 DUK_HOBJECT_INCREF(thr, obj_global);
58449 } else {
58450 /* This may only happen if built-ins are being "torn down".
58451 * This behavior is out of specification scope.
58452 */
58453 DUK_D(DUK_DPRINT("this binding: wanted to use global object, but it is NULL -> using undefined instead"));
58454 DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv_this)); /* no need to decref previous value */
58455 DUK_TVAL_SET_UNDEFINED(tv_this); /* nothing to incref */
58456 }
58457 break;
58458 default:
58459 /* Plain buffers and lightfuncs are object coerced. Lightfuncs
58460 * very rarely come here however, because the call target would
58461 * need to be a strict non-lightfunc (lightfuncs are considered
58462 * strict) with an explicit lightfunc 'this' binding.
58463 */
58464 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_this));
58465 DUK_DDD(DUK_DDDPRINT("this binding: non-strict, not object/undefined/null -> use ToObject(value)"));
58466 duk_to_object(ctx, idx_this); /* may have side effects */
58467 break;
58468 }
58469}
58470
58471/*
58472 * Shared helper for non-bound func lookup.
58473 *
58474 * Returns duk_hobject * to the final non-bound function (NULL for lightfunc).
58475 */
58476
58477DUK_LOCAL duk_hobject *duk__nonbound_func_lookup(duk_context *ctx,
58478 duk_idx_t idx_func,
58479 duk_idx_t *out_num_stack_args,
58480 duk_tval **out_tv_func,
58481 duk_small_uint_t call_flags) {
58482 duk_hthread *thr = (duk_hthread *) ctx;
58483 duk_tval *tv_func;
58484 duk_hobject *func;
58485
58486 for (;;) {
58487 /* Use loop to minimize code size of relookup after bound function case */
58488 tv_func = DUK_GET_TVAL_POSIDX(ctx, idx_func);
58489 DUK_ASSERT(tv_func != NULL);
58490
58491 if (DUK_TVAL_IS_OBJECT(tv_func)) {
58492 func = DUK_TVAL_GET_OBJECT(tv_func);
58493 if (!DUK_HOBJECT_IS_CALLABLE(func)) {
58494 goto not_callable_error;
58495 }
58496 if (DUK_HOBJECT_HAS_BOUNDFUNC(func)) {
58497 duk__handle_bound_chain_for_call(thr, idx_func, out_num_stack_args, call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL);
58498
58499 /* The final object may be a normal function or a lightfunc.
58500 * We need to re-lookup tv_func because it may have changed
58501 * (also value stack may have been resized). Loop again to
58502 * do that; we're guaranteed not to come here again.
58503 */
58504 DUK_ASSERT(DUK_TVAL_IS_OBJECT(duk_require_tval(ctx, idx_func)) ||
58505 DUK_TVAL_IS_LIGHTFUNC(duk_require_tval(ctx, idx_func)));
58506 continue;
58507 }
58508 } else if (DUK_TVAL_IS_LIGHTFUNC(tv_func)) {
58509 func = NULL;
58510 } else {
58511 goto not_callable_error;
58512 }
58513 break;
58514 }
58515
58516 DUK_ASSERT((DUK_TVAL_IS_OBJECT(tv_func) && DUK_HOBJECT_IS_CALLABLE(DUK_TVAL_GET_OBJECT(tv_func))) ||
58517 DUK_TVAL_IS_LIGHTFUNC(tv_func));
58518 DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func));
58519 DUK_ASSERT(func == NULL || (DUK_HOBJECT_IS_COMPFUNC(func) ||
58520 DUK_HOBJECT_IS_NATFUNC(func)));
58521
58522 *out_tv_func = tv_func;
58523 return func;
58524
58525 not_callable_error:
58526 DUK_ASSERT(tv_func != NULL);
58527#if defined(DUK_USE_PARANOID_ERRORS)
58528 DUK_ERROR_TYPE(thr, DUK_STR_NOT_CALLABLE);
58529#else
58530 DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "%s not callable", duk_push_string_tval_readable(ctx, tv_func));
58531#endif
58532 DUK_UNREACHABLE();
58533 return NULL; /* never executed */
58534}
58535
58536/*
58537 * Value stack resize and stack top adjustment helper.
58538 *
58539 * XXX: This should all be merged to duk_valstack_resize_raw().
58540 */
58541
58542DUK_LOCAL void duk__adjust_valstack_and_top(duk_hthread *thr,
58543 duk_idx_t num_stack_args,
58544 duk_idx_t idx_args,
58545 duk_idx_t nregs,
58546 duk_idx_t nargs,
58547 duk_hobject *func) {
58548 duk_context *ctx = (duk_context *) thr;
58549 duk_size_t vs_min_size;
58550 duk_bool_t adjusted_top = 0;
58551
58552 vs_min_size = (thr->valstack_bottom - thr->valstack) + /* bottom of current func */
58553 idx_args; /* bottom of new func */
58554
58555 if (nregs >= 0) {
58556 DUK_ASSERT(nargs >= 0);
58557 DUK_ASSERT(nregs >= nargs);
58558 vs_min_size += nregs;
58559 } else {
58560 /* 'func' wants stack "as is" */
58561 vs_min_size += num_stack_args; /* num entries of new func at entry */
58562 }
58563 if (func == NULL || DUK_HOBJECT_IS_NATFUNC(func)) {
58564 vs_min_size += DUK_VALSTACK_API_ENTRY_MINIMUM; /* Duktape/C API guaranteed entries (on top of args) */
58565 }
58566 vs_min_size += DUK_VALSTACK_INTERNAL_EXTRA; /* + spare */
58567
58568 /* XXX: We can't resize the value stack to a size smaller than the
58569 * current top, so the order of the resize and adjusting the stack
58570 * top depends on the current vs. final size of the value stack.
58571 * The operations could be combined to avoid this, but the proper
58572 * fix is to only grow the value stack on a function call, and only
58573 * shrink it (without throwing if the shrink fails) on function
58574 * return.
58575 */
58576
58577 if (vs_min_size < (duk_size_t) (thr->valstack_top - thr->valstack)) {
58578 DUK_DDD(DUK_DDDPRINT(("final size smaller, set top before resize")));
58579
58580 DUK_ASSERT(nregs >= 0); /* can't happen when keeping current stack size */
58581 duk_set_top(ctx, idx_args + nargs); /* clamp anything above nargs */
58582 duk_set_top(ctx, idx_args + nregs); /* extend with undefined */
58583 adjusted_top = 1;
58584 }
58585
58586 (void) duk_valstack_resize_raw((duk_context *) thr,
58587 vs_min_size,
58588 DUK_VSRESIZE_FLAG_SHRINK | /* flags */
58589 0 /* no compact */ |
58590 DUK_VSRESIZE_FLAG_THROW);
58591
58592 if (!adjusted_top) {
58593 if (nregs >= 0) {
58594 DUK_ASSERT(nregs >= nargs);
58595 duk_set_top(ctx, idx_args + nargs); /* clamp anything above nargs */
58596 duk_set_top(ctx, idx_args + nregs); /* extend with undefined */
58597 }
58598 }
58599}
58600
58601/*
58602 * Manipulate value stack so that exactly 'num_stack_rets' return
58603 * values are at 'idx_retbase' in every case, assuming there are
58604 * 'rc' return values on top of stack.
58605 *
58606 * This is a bit tricky, because the called C function operates in
58607 * the same activation record and may have e.g. popped the stack
58608 * empty (below idx_retbase).
58609 */
58610
58611DUK_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) {
58612 duk_context *ctx = (duk_context *) thr;
58613 duk_idx_t idx_rcbase;
58614
58615 DUK_ASSERT(thr != NULL);
58616 DUK_ASSERT(idx_retbase >= 0);
58617 DUK_ASSERT(num_stack_rets >= 0);
58618 DUK_ASSERT(num_actual_rets >= 0);
58619
58620 idx_rcbase = duk_get_top(ctx) - num_actual_rets; /* base of known return values */
58621
58622 DUK_DDD(DUK_DDDPRINT("adjust valstack after func call: "
58623 "num_stack_rets=%ld, num_actual_rets=%ld, stack_top=%ld, idx_retbase=%ld, idx_rcbase=%ld",
58624 (long) num_stack_rets, (long) num_actual_rets, (long) duk_get_top(ctx),
58625 (long) idx_retbase, (long) idx_rcbase));
58626
58627 DUK_ASSERT(idx_rcbase >= 0); /* caller must check */
58628
58629 /* Ensure space for final configuration (idx_retbase + num_stack_rets)
58630 * and intermediate configurations.
58631 */
58632 duk_require_stack_top(ctx,
58633 (idx_rcbase > idx_retbase ? idx_rcbase : idx_retbase) +
58634 num_stack_rets);
58635
58636 /* Chop extra retvals away / extend with undefined. */
58637 duk_set_top(ctx, idx_rcbase + num_stack_rets);
58638
58639 if (idx_rcbase >= idx_retbase) {
58640 duk_idx_t count = idx_rcbase - idx_retbase;
58641 duk_idx_t i;
58642
58643 DUK_DDD(DUK_DDDPRINT("elements at/after idx_retbase have enough to cover func retvals "
58644 "(idx_retbase=%ld, idx_rcbase=%ld)", (long) idx_retbase, (long) idx_rcbase));
58645
58646 /* nuke values at idx_retbase to get the first retval (initially
58647 * at idx_rcbase) to idx_retbase
58648 */
58649
58650 DUK_ASSERT(count >= 0);
58651
58652 for (i = 0; i < count; i++) {
58653 /* XXX: inefficient; block remove primitive */
58654 duk_remove(ctx, idx_retbase);
58655 }
58656 } else {
58657 duk_idx_t count = idx_retbase - idx_rcbase;
58658 duk_idx_t i;
58659
58660 DUK_DDD(DUK_DDDPRINT("not enough elements at/after idx_retbase to cover func retvals "
58661 "(idx_retbase=%ld, idx_rcbase=%ld)", (long) idx_retbase, (long) idx_rcbase));
58662
58663 /* insert 'undefined' values at idx_rcbase to get the
58664 * return values to idx_retbase
58665 */
58666
58667 DUK_ASSERT(count > 0);
58668
58669 for (i = 0; i < count; i++) {
58670 /* XXX: inefficient; block insert primitive */
58671 duk_push_undefined(ctx);
58672 duk_insert(ctx, idx_rcbase);
58673 }
58674 }
58675}
58676
58677/*
58678 * Misc shared helpers.
58679 */
58680
58681/* Get valstack index for the func argument or throw if insane stack. */
58682DUK_LOCAL duk_idx_t duk__get_idx_func(duk_hthread *thr, duk_idx_t num_stack_args) {
58683 duk_size_t off_stack_top;
58684 duk_size_t off_stack_args;
58685 duk_size_t off_stack_all;
58686 duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
58687
58688 /* Argument validation and func/args offset. */
58689 off_stack_top = (duk_size_t) ((duk_uint8_t *) thr->valstack_top - (duk_uint8_t *) thr->valstack_bottom);
58690 off_stack_args = (duk_size_t) ((duk_size_t) num_stack_args * sizeof(duk_tval));
58691 off_stack_all = off_stack_args + 2 * sizeof(duk_tval);
58692 if (DUK_UNLIKELY(off_stack_all > off_stack_top)) {
58693 /* Since stack indices are not reliable, we can't do anything useful
58694 * here. Invoke the existing setjmp catcher, or if it doesn't exist,
58695 * call the fatal error handler.
58696 */
58697 DUK_ERROR_TYPE_INVALID_ARGS(thr);
58698 return 0;
58699 }
58700 idx_func = (duk_idx_t) ((off_stack_top - off_stack_all) / sizeof(duk_tval));
58701 return idx_func;
58702}
58703
58704/*
58705 * duk_handle_call_protected() and duk_handle_call_unprotected():
58706 * call into a Duktape/C or an Ecmascript function from any state.
58707 *
58708 * Input stack (thr):
58709 *
58710 * [ func this arg1 ... argN ]
58711 *
58712 * Output stack (thr):
58713 *
58714 * [ retval ] (DUK_EXEC_SUCCESS)
58715 * [ errobj ] (DUK_EXEC_ERROR (normal error), protected call)
58716 *
58717 * Even when executing a protected call an error may be thrown in rare cases
58718 * such as an insane num_stack_args argument. If there is no catchpoint for
58719 * such errors, the fatal error handler is called.
58720 *
58721 * The error handling path should be error free, even for out-of-memory
58722 * errors, to ensure safe sandboxing. (As of Duktape 1.4.0 this is not
58723 * yet the case, see XXX notes below.)
58724 */
58725
58726DUK_INTERNAL duk_int_t duk_handle_call_protected(duk_hthread *thr,
58727 duk_idx_t num_stack_args,
58728 duk_small_uint_t call_flags) {
58729 duk_context *ctx;
58730 duk_size_t entry_valstack_bottom_index;
58731 duk_size_t entry_valstack_end;
58732 duk_size_t entry_callstack_top;
58733 duk_size_t entry_catchstack_top;
58734 duk_int_t entry_call_recursion_depth;
58735 duk_hthread *entry_curr_thread;
58736 duk_uint_fast8_t entry_thread_state;
58737 duk_instr_t **entry_ptr_curr_pc;
58738 duk_jmpbuf *old_jmpbuf_ptr = NULL;
58739 duk_jmpbuf our_jmpbuf;
58740 duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
58741
58742 /* XXX: Multiple tv_func lookups are now avoided by making a local
58743 * copy of tv_func. Another approach would be to compute an offset
58744 * for tv_func from valstack bottom and recomputing the tv_func
58745 * pointer quickly as valstack + offset instead of calling duk_get_tval().
58746 */
58747
58748 ctx = (duk_context *) thr;
58749 DUK_UNREF(ctx);
58750 DUK_ASSERT(thr != NULL);
58751 DUK_ASSERT_CTX_VALID(ctx);
58752 DUK_ASSERT(num_stack_args >= 0);
58753 /* XXX: currently NULL allocations are not supported; remove if later allowed */
58754 DUK_ASSERT(thr->valstack != NULL);
58755 DUK_ASSERT(thr->callstack != NULL);
58756 DUK_ASSERT(thr->catchstack != NULL);
58757
58758 /* Argument validation and func/args offset. */
58759 idx_func = duk__get_idx_func(thr, num_stack_args);
58760
58761 /* Preliminaries, required by setjmp() handler. Must be careful not
58762 * to throw an unintended error here.
58763 */
58764
58765 entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
58766#if defined(DUK_USE_PREFER_SIZE)
58767 entry_valstack_end = (duk_size_t) (thr->valstack_end - thr->valstack);
58768#else
58769 DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack) == thr->valstack_size);
58770 entry_valstack_end = thr->valstack_size;
58771#endif
58772 entry_callstack_top = thr->callstack_top;
58773 entry_catchstack_top = thr->catchstack_top;
58774 entry_call_recursion_depth = thr->heap->call_recursion_depth;
58775 entry_curr_thread = thr->heap->curr_thread; /* Note: may be NULL if first call */
58776 entry_thread_state = thr->state;
58777 entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
58778
58779 DUK_DD(DUK_DDPRINT("duk_handle_call_protected: thr=%p, num_stack_args=%ld, "
58780 "call_flags=0x%08lx (ignorerec=%ld, constructor=%ld), "
58781 "valstack_top=%ld, idx_func=%ld, idx_args=%ld, rec_depth=%ld/%ld, "
58782 "entry_valstack_bottom_index=%ld, entry_callstack_top=%ld, entry_catchstack_top=%ld, "
58783 "entry_call_recursion_depth=%ld, entry_curr_thread=%p, entry_thread_state=%ld",
58784 (void *) thr,
58785 (long) num_stack_args,
58786 (unsigned long) call_flags,
58787 (long) ((call_flags & DUK_CALL_FLAG_IGNORE_RECLIMIT) != 0 ? 1 : 0),
58788 (long) ((call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL) != 0 ? 1 : 0),
58789 (long) duk_get_top(ctx),
58790 (long) idx_func,
58791 (long) (idx_func + 2),
58792 (long) thr->heap->call_recursion_depth,
58793 (long) thr->heap->call_recursion_limit,
58794 (long) entry_valstack_bottom_index,
58795 (long) entry_callstack_top,
58796 (long) entry_catchstack_top,
58797 (long) entry_call_recursion_depth,
58798 (void *) entry_curr_thread,
58799 (long) entry_thread_state));
58800
58801 old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr;
58802 thr->heap->lj.jmpbuf_ptr = &our_jmpbuf;
58803
58804#if defined(DUK_USE_CPP_EXCEPTIONS)
58805 try {
58806#else
58807 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == &our_jmpbuf);
58808 if (DUK_SETJMP(our_jmpbuf.jb) == 0) {
58809#endif
58810 /* Call handling and success path. Success path exit cleans
58811 * up almost all state.
58812 */
58813 duk__handle_call_inner(thr, num_stack_args, call_flags, idx_func);
58814
58815 /* Success path handles */
58816 DUK_ASSERT(thr->heap->call_recursion_depth == entry_call_recursion_depth);
58817 DUK_ASSERT(thr->ptr_curr_pc == entry_ptr_curr_pc);
58818
58819 /* Longjmp state is kept clean in success path */
58820 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
58821 DUK_ASSERT(thr->heap->lj.iserror == 0);
58822 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
58823 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
58824
58825 thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
58826
58827 return DUK_EXEC_SUCCESS;
58828#if defined(DUK_USE_CPP_EXCEPTIONS)
58829 } catch (duk_internal_exception &exc) {
58830#else
58831 } else {
58832#endif
58833 /* Error; error value is in heap->lj.value1. */
58834
58835#if defined(DUK_USE_CPP_EXCEPTIONS)
58836 DUK_UNREF(exc);
58837#endif
58838
58839 duk__handle_call_error(thr,
58840 entry_valstack_bottom_index,
58841 entry_valstack_end,
58842 entry_catchstack_top,
58843 entry_callstack_top,
58844 entry_call_recursion_depth,
58845 entry_curr_thread,
58846 entry_thread_state,
58847 entry_ptr_curr_pc,
58848 idx_func,
58849 old_jmpbuf_ptr);
58850
58851 /* Longjmp state is cleaned up by error handling */
58852 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
58853 DUK_ASSERT(thr->heap->lj.iserror == 0);
58854 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
58855 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
58856 return DUK_EXEC_ERROR;
58857 }
58858#if defined(DUK_USE_CPP_EXCEPTIONS)
58859 catch (std::exception &exc) {
58860 const char *what = exc.what();
58861 if (!what) {
58862 what = "unknown";
58863 }
58864 DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
58865 try {
58866 DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
58867 } catch (duk_internal_exception exc) {
58868 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
58869 DUK_UNREF(exc);
58870 duk__handle_call_error(thr,
58871 entry_valstack_bottom_index,
58872 entry_valstack_end,
58873 entry_catchstack_top,
58874 entry_callstack_top,
58875 entry_call_recursion_depth,
58876 entry_curr_thread,
58877 entry_thread_state,
58878 entry_ptr_curr_pc,
58879 idx_func,
58880 old_jmpbuf_ptr);
58881 return DUK_EXEC_ERROR;
58882 }
58883 } catch (...) {
58884 DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
58885 try {
58886 DUK_ERROR_TYPE(thr, "caught invalid c++ exception (perhaps thrown by user code)");
58887 } catch (duk_internal_exception exc) {
58888 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
58889 DUK_UNREF(exc);
58890 duk__handle_call_error(thr,
58891 entry_valstack_bottom_index,
58892 entry_valstack_end,
58893 entry_catchstack_top,
58894 entry_callstack_top,
58895 entry_call_recursion_depth,
58896 entry_curr_thread,
58897 entry_thread_state,
58898 entry_ptr_curr_pc,
58899 idx_func,
58900 old_jmpbuf_ptr);
58901 return DUK_EXEC_ERROR;
58902 }
58903 }
58904#endif
58905}
58906
58907DUK_INTERNAL void duk_handle_call_unprotected(duk_hthread *thr,
58908 duk_idx_t num_stack_args,
58909 duk_small_uint_t call_flags) {
58910 duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
58911
58912 /* Argument validation and func/args offset. */
58913 idx_func = duk__get_idx_func(thr, num_stack_args);
58914
58915 duk__handle_call_inner(thr, num_stack_args, call_flags, idx_func);
58916}
58917
58918DUK_LOCAL void duk__handle_call_inner(duk_hthread *thr,
58919 duk_idx_t num_stack_args,
58920 duk_small_uint_t call_flags,
58921 duk_idx_t idx_func) {
58922 duk_context *ctx;
58923 duk_size_t entry_valstack_bottom_index;
58924 duk_size_t entry_valstack_end;
58925 duk_size_t entry_callstack_top;
58926 duk_size_t entry_catchstack_top;
58927 duk_int_t entry_call_recursion_depth;
58928 duk_hthread *entry_curr_thread;
58929 duk_uint_fast8_t entry_thread_state;
58930 duk_instr_t **entry_ptr_curr_pc;
58931 duk_idx_t nargs; /* # argument registers target function wants (< 0 => "as is") */
58932 duk_idx_t nregs; /* # total registers target function wants on entry (< 0 => "as is") */
58933 duk_hobject *func; /* 'func' on stack (borrowed reference) */
58934 duk_tval *tv_func; /* duk_tval ptr for 'func' on stack (borrowed reference) or tv_func_copy */
58935 duk_tval tv_func_copy; /* to avoid relookups */
58936 duk_activation *act;
58937 duk_hobject *env;
58938 duk_ret_t rc;
58939
58940 ctx = (duk_context *) thr;
58941 DUK_ASSERT(thr != NULL);
58942 DUK_ASSERT_CTX_VALID(ctx);
58943 DUK_ASSERT(ctx != NULL);
58944 DUK_ASSERT(num_stack_args >= 0);
58945 /* XXX: currently NULL allocations are not supported; remove if later allowed */
58946 DUK_ASSERT(thr->valstack != NULL);
58947 DUK_ASSERT(thr->callstack != NULL);
58948 DUK_ASSERT(thr->catchstack != NULL);
58949
58950 DUK_DD(DUK_DDPRINT("duk__handle_call_inner: num_stack_args=%ld, call_flags=0x%08lx, top=%ld",
58951 (long) num_stack_args, (long) call_flags, (long) duk_get_top(ctx)));
58952
58953 /*
58954 * Store entry state.
58955 */
58956
58957 entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
58958#if defined(DUK_USE_PREFER_SIZE)
58959 entry_valstack_end = (duk_size_t) (thr->valstack_end - thr->valstack);
58960#else
58961 DUK_ASSERT((duk_size_t) (thr->valstack_end - thr->valstack) == thr->valstack_size);
58962 entry_valstack_end = thr->valstack_size;
58963#endif
58964 entry_callstack_top = thr->callstack_top;
58965 entry_catchstack_top = thr->catchstack_top;
58966 entry_call_recursion_depth = thr->heap->call_recursion_depth;
58967 entry_curr_thread = thr->heap->curr_thread; /* Note: may be NULL if first call */
58968 entry_thread_state = thr->state;
58969 entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
58970
58971 /* If thr->ptr_curr_pc is set, sync curr_pc to act->pc. Then NULL
58972 * thr->ptr_curr_pc so that it's not accidentally used with an incorrect
58973 * activation when side effects occur.
58974 */
58975 duk_hthread_sync_and_null_currpc(thr);
58976
58977 DUK_DD(DUK_DDPRINT("duk__handle_call_inner: thr=%p, num_stack_args=%ld, "
58978 "call_flags=0x%08lx (ignorerec=%ld, constructor=%ld), "
58979 "valstack_top=%ld, idx_func=%ld, idx_args=%ld, rec_depth=%ld/%ld, "
58980 "entry_valstack_bottom_index=%ld, entry_callstack_top=%ld, entry_catchstack_top=%ld, "
58981 "entry_call_recursion_depth=%ld, entry_curr_thread=%p, entry_thread_state=%ld",
58982 (void *) thr,
58983 (long) num_stack_args,
58984 (unsigned long) call_flags,
58985 (long) ((call_flags & DUK_CALL_FLAG_IGNORE_RECLIMIT) != 0 ? 1 : 0),
58986 (long) ((call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL) != 0 ? 1 : 0),
58987 (long) duk_get_top(ctx),
58988 (long) idx_func,
58989 (long) (idx_func + 2),
58990 (long) thr->heap->call_recursion_depth,
58991 (long) thr->heap->call_recursion_limit,
58992 (long) entry_valstack_bottom_index,
58993 (long) entry_callstack_top,
58994 (long) entry_catchstack_top,
58995 (long) entry_call_recursion_depth,
58996 (void *) entry_curr_thread,
58997 (long) entry_thread_state));
58998
58999
59000 /*
59001 * Thread state check and book-keeping.
59002 */
59003
59004 if (thr == thr->heap->curr_thread) {
59005 /* same thread */
59006 if (thr->state != DUK_HTHREAD_STATE_RUNNING) {
59007 /* should actually never happen, but check anyway */
59008 goto thread_state_error;
59009 }
59010 } else {
59011 /* different thread */
59012 DUK_ASSERT(thr->heap->curr_thread == NULL ||
59013 thr->heap->curr_thread->state == DUK_HTHREAD_STATE_RUNNING);
59014 if (thr->state != DUK_HTHREAD_STATE_INACTIVE) {
59015 goto thread_state_error;
59016 }
59017 DUK_HEAP_SWITCH_THREAD(thr->heap, thr);
59018 thr->state = DUK_HTHREAD_STATE_RUNNING;
59019
59020 /* Note: multiple threads may be simultaneously in the RUNNING
59021 * state, but not in the same "resume chain".
59022 */
59023 }
59024 DUK_ASSERT(thr->heap->curr_thread == thr);
59025 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
59026
59027 /*
59028 * C call recursion depth check, which provides a reasonable upper
59029 * bound on maximum C stack size (arbitrary C stack growth is only
59030 * possible by recursive handle_call / handle_safe_call calls).
59031 */
59032
59033 /* XXX: remove DUK_CALL_FLAG_IGNORE_RECLIMIT flag: there's now the
59034 * reclimit bump?
59035 */
59036
59037 DUK_ASSERT(thr->heap->call_recursion_depth >= 0);
59038 DUK_ASSERT(thr->heap->call_recursion_depth <= thr->heap->call_recursion_limit);
59039 if (call_flags & DUK_CALL_FLAG_IGNORE_RECLIMIT) {
59040 DUK_DD(DUK_DDPRINT("ignoring reclimit for this call (probably an errhandler call)"));
59041 } else {
59042 if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit) {
59043 /* XXX: error message is a bit misleading: we reached a recursion
59044 * limit which is also essentially the same as a C callstack limit
59045 * (except perhaps with some relaxed threading assumptions).
59046 */
59047 DUK_ERROR_RANGE(thr, DUK_STR_C_CALLSTACK_LIMIT);
59048 }
59049 thr->heap->call_recursion_depth++;
59050 }
59051
59052 /*
59053 * Check the function type, handle bound function chains, and prepare
59054 * parameters for the rest of the call handling. Also figure out the
59055 * effective 'this' binding, which replaces the current value at
59056 * idx_func + 1.
59057 *
59058 * If the target function is a 'bound' one, follow the chain of 'bound'
59059 * functions until a non-bound function is found. During this process,
59060 * bound arguments are 'prepended' to existing ones, and the "this"
59061 * binding is overridden. See E5 Section 15.3.4.5.1.
59062 *
59063 * Lightfunc detection happens here too. Note that lightweight functions
59064 * can be wrapped by (non-lightweight) bound functions so we must resolve
59065 * the bound function chain first.
59066 */
59067
59068 func = duk__nonbound_func_lookup(ctx, idx_func, &num_stack_args, &tv_func, call_flags);
59069 DUK_TVAL_SET_TVAL(&tv_func_copy, tv_func);
59070 tv_func = &tv_func_copy; /* local copy to avoid relookups */
59071
59072 DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func));
59073 DUK_ASSERT(func == NULL || (DUK_HOBJECT_IS_COMPFUNC(func) ||
59074 DUK_HOBJECT_IS_NATFUNC(func)));
59075
59076 duk__coerce_effective_this_binding(thr, func, idx_func + 1);
59077 DUK_DDD(DUK_DDDPRINT("effective 'this' binding is: %!T",
59078 (duk_tval *) duk_get_tval(ctx, idx_func + 1)));
59079
59080 /* [ ... func this arg1 ... argN ] */
59081
59082 /*
59083 * Setup a preliminary activation and figure out nargs/nregs.
59084 *
59085 * Don't touch valstack_bottom or valstack_top yet so that Duktape API
59086 * calls work normally.
59087 */
59088
59089 duk_hthread_callstack_grow(thr);
59090
59091 if (thr->callstack_top > 0) {
59092 /*
59093 * Update idx_retval of current activation.
59094 *
59095 * Although it might seem this is not necessary (bytecode executor
59096 * does this for Ecmascript-to-Ecmascript calls; other calls are
59097 * handled here), this turns out to be necessary for handling yield
59098 * and resume. For them, an Ecmascript-to-native call happens, and
59099 * the Ecmascript call's idx_retval must be set for things to work.
59100 */
59101
59102 (thr->callstack + thr->callstack_top - 1)->idx_retval = entry_valstack_bottom_index + idx_func;
59103 }
59104
59105 DUK_ASSERT(thr->callstack_top < thr->callstack_size);
59106 act = thr->callstack + thr->callstack_top;
59107 thr->callstack_top++;
59108 DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
59109 DUK_ASSERT(thr->valstack_top > thr->valstack_bottom); /* at least effective 'this' */
59110 DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func));
59111
59112 act->flags = 0;
59113
59114 /* For now all calls except Ecma-to-Ecma calls prevent a yield. */
59115 act->flags |= DUK_ACT_FLAG_PREVENT_YIELD;
59116 if (call_flags & DUK_CALL_FLAG_CONSTRUCTOR_CALL) {
59117 act->flags |= DUK_ACT_FLAG_CONSTRUCT;
59118 }
59119 if (call_flags & DUK_CALL_FLAG_DIRECT_EVAL) {
59120 act->flags |= DUK_ACT_FLAG_DIRECT_EVAL;
59121 }
59122
59123 /* These base values are never used, but if the compiler doesn't know
59124 * that DUK_ERROR() won't return, these are needed to silence warnings.
59125 * On the other hand, scan-build will warn about the values not being
59126 * used, so add a DUK_UNREF.
59127 */
59128 nargs = 0; DUK_UNREF(nargs);
59129 nregs = 0; DUK_UNREF(nregs);
59130
59131 if (DUK_LIKELY(func != NULL)) {
59132 if (DUK_HOBJECT_HAS_STRICT(func)) {
59133 act->flags |= DUK_ACT_FLAG_STRICT;
59134 }
59135 if (DUK_HOBJECT_IS_COMPFUNC(func)) {
59136 nargs = ((duk_hcompfunc *) func)->nargs;
59137 nregs = ((duk_hcompfunc *) func)->nregs;
59138 DUK_ASSERT(nregs >= nargs);
59139 } else {
59140 /* True because of call target lookup checks. */
59141 DUK_ASSERT(DUK_HOBJECT_IS_NATFUNC(func));
59142
59143 /* Note: nargs (and nregs) may be negative for a native,
59144 * function, which indicates that the function wants the
59145 * input stack "as is" (i.e. handles "vararg" arguments).
59146 */
59147 nargs = ((duk_hnatfunc *) func)->nargs;
59148 nregs = nargs;
59149 }
59150 } else {
59151 duk_small_uint_t lf_flags;
59152
59153 DUK_ASSERT(DUK_TVAL_IS_LIGHTFUNC(tv_func));
59154 lf_flags = DUK_TVAL_GET_LIGHTFUNC_FLAGS(tv_func);
59155 nargs = DUK_LFUNC_FLAGS_GET_NARGS(lf_flags);
59156 if (nargs == DUK_LFUNC_NARGS_VARARGS) {
59157 nargs = -1; /* vararg */
59158 }
59159 nregs = nargs;
59160
59161 act->flags |= DUK_ACT_FLAG_STRICT;
59162 }
59163
59164 act->func = func; /* NULL for lightfunc */
59165 act->var_env = NULL;
59166 act->lex_env = NULL;
59167#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
59168 act->prev_caller = NULL;
59169#endif
59170 act->curr_pc = NULL;
59171#if defined(DUK_USE_DEBUGGER_SUPPORT)
59172 act->prev_line = 0;
59173#endif
59174 act->idx_bottom = entry_valstack_bottom_index + idx_func + 2;
59175#if 0 /* topmost activation idx_retval is considered garbage, no need to init */
59176 act->idx_retval = 0;
59177#endif
59178 DUK_TVAL_SET_TVAL(&act->tv_func, tv_func); /* borrowed, no refcount */
59179
59180 /* XXX: remove the preventcount and make yield walk the callstack?
59181 * Or perhaps just use a single flag, not a counter, faster to just
59182 * set and restore?
59183 */
59184 if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
59185 /* duk_hthread_callstack_unwind() will decrease this on unwind */
59186 thr->callstack_preventcount++;
59187 }
59188
59189 /* XXX: Is this INCREF necessary? 'func' is always a borrowed
59190 * reference reachable through the value stack? If changed, stack
59191 * unwind code also needs to be fixed to match.
59192 */
59193 DUK_HOBJECT_INCREF_ALLOWNULL(thr, func); /* act->func */
59194
59195#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
59196 if (func) {
59197 duk__update_func_caller_prop(thr, func);
59198 }
59199 act = thr->callstack + thr->callstack_top - 1;
59200#endif
59201
59202 /* [ ... func this arg1 ... argN ] */
59203
59204 /*
59205 * Environment record creation and 'arguments' object creation.
59206 * Named function expression name binding is handled by the
59207 * compiler; the compiled function's parent env will contain
59208 * the (immutable) binding already.
59209 *
59210 * This handling is now identical for C and Ecmascript functions.
59211 * C functions always have the 'NEWENV' flag set, so their
59212 * environment record initialization is delayed (which is good).
59213 *
59214 * Delayed creation (on demand) is handled in duk_js_var.c.
59215 */
59216
59217 DUK_ASSERT(func == NULL || !DUK_HOBJECT_HAS_BOUNDFUNC(func)); /* bound function chain has already been resolved */
59218
59219 if (DUK_LIKELY(func != NULL)) {
59220 if (DUK_LIKELY(DUK_HOBJECT_HAS_NEWENV(func))) {
59221 if (DUK_LIKELY(!DUK_HOBJECT_HAS_CREATEARGS(func))) {
59222 /* Use a new environment but there's no 'arguments' object;
59223 * delayed environment initialization. This is the most
59224 * common case.
59225 */
59226 DUK_ASSERT(act->lex_env == NULL);
59227 DUK_ASSERT(act->var_env == NULL);
59228 } else {
59229 /* Use a new environment and there's an 'arguments' object.
59230 * We need to initialize it right now.
59231 */
59232
59233 /* third arg: absolute index (to entire valstack) of idx_bottom of new activation */
59234 env = duk_create_activation_environment_record(thr, func, act->idx_bottom);
59235 DUK_ASSERT(env != NULL);
59236
59237 /* [ ... func this arg1 ... argN envobj ] */
59238
59239 DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
59240 duk__handle_createargs_for_call(thr, func, env, num_stack_args);
59241
59242 /* [ ... func this arg1 ... argN envobj ] */
59243
59244 act = thr->callstack + thr->callstack_top - 1;
59245 act->lex_env = env;
59246 act->var_env = env;
59247 DUK_HOBJECT_INCREF(thr, env);
59248 DUK_HOBJECT_INCREF(thr, env); /* XXX: incref by count (2) directly */
59249 duk_pop(ctx);
59250 }
59251 } else {
59252 /* Use existing env (e.g. for non-strict eval); cannot have
59253 * an own 'arguments' object (but can refer to an existing one).
59254 */
59255
59256 DUK_ASSERT(!DUK_HOBJECT_HAS_CREATEARGS(func));
59257
59258 duk__handle_oldenv_for_call(thr, func, act);
59259
59260 DUK_ASSERT(act->lex_env != NULL);
59261 DUK_ASSERT(act->var_env != NULL);
59262 }
59263 } else {
59264 /* Lightfuncs are always native functions and have "newenv". */
59265 DUK_ASSERT(act->lex_env == NULL);
59266 DUK_ASSERT(act->var_env == NULL);
59267 }
59268
59269 /* [ ... func this arg1 ... argN ] */
59270
59271 /*
59272 * Setup value stack: clamp to 'nargs', fill up to 'nregs'
59273 *
59274 * Value stack may either grow or shrink, depending on the
59275 * number of func registers and the number of actual arguments.
59276 * If nregs >= 0, func wants args clamped to 'nargs'; else it
59277 * wants all args (= 'num_stack_args').
59278 */
59279
59280 /* XXX: optimize value stack operation */
59281 /* XXX: don't want to shrink allocation here */
59282
59283 duk__adjust_valstack_and_top(thr,
59284 num_stack_args,
59285 idx_func + 2,
59286 nregs,
59287 nargs,
59288 func);
59289
59290 /*
59291 * Determine call type, then finalize activation, shift to
59292 * new value stack bottom, and call the target.
59293 */
59294
59295 if (func != NULL && DUK_HOBJECT_IS_COMPFUNC(func)) {
59296 /*
59297 * Ecmascript call
59298 */
59299
59300 duk_tval *tv_ret;
59301 duk_tval *tv_funret;
59302
59303 DUK_ASSERT(func != NULL);
59304 DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func));
59305 act->curr_pc = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) func);
59306
59307 thr->valstack_bottom = thr->valstack_bottom + idx_func + 2;
59308 /* keep current valstack_top */
59309 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
59310 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
59311 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
59312
59313 /* [ ... func this | arg1 ... argN ] ('this' must precede new bottom) */
59314
59315 /*
59316 * Bytecode executor call.
59317 *
59318 * Execute bytecode, handling any recursive function calls and
59319 * thread resumptions. Returns when execution would return from
59320 * the entry level activation. When the executor returns, a
59321 * single return value is left on the stack top.
59322 *
59323 * The only possible longjmp() is an error (DUK_LJ_TYPE_THROW),
59324 * other types are handled internally by the executor.
59325 */
59326
59327 /* thr->ptr_curr_pc is set by bytecode executor early on entry */
59328 DUK_ASSERT(thr->ptr_curr_pc == NULL);
59329 DUK_DDD(DUK_DDDPRINT("entering bytecode execution"));
59330 duk_js_execute_bytecode(thr);
59331 DUK_DDD(DUK_DDDPRINT("returned from bytecode execution"));
59332
59333 /* Unwind. */
59334
59335 DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top); /* may need unwind */
59336 DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
59337 DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
59338 duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
59339 duk_hthread_catchstack_shrink_check(thr);
59340 duk_hthread_callstack_unwind(thr, entry_callstack_top);
59341 duk_hthread_callstack_shrink_check(thr);
59342
59343 thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
59344 /* keep current valstack_top */
59345 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
59346 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
59347 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
59348 DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= idx_func + 1);
59349
59350 /* Return value handling. */
59351
59352 /* [ ... func this (crud) retval ] */
59353
59354 tv_ret = thr->valstack_bottom + idx_func;
59355 tv_funret = thr->valstack_top - 1;
59356#if defined(DUK_USE_FASTINT)
59357 /* Explicit check for fastint downgrade. */
59358 DUK_TVAL_CHKFAST_INPLACE_FAST(tv_funret);
59359#endif
59360 DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, tv_funret); /* side effects */
59361 } else {
59362 /*
59363 * Native call.
59364 */
59365
59366 duk_tval *tv_ret;
59367 duk_tval *tv_funret;
59368
59369 thr->valstack_bottom = thr->valstack_bottom + idx_func + 2;
59370 /* keep current valstack_top */
59371 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
59372 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
59373 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
59374 DUK_ASSERT(func == NULL || ((duk_hnatfunc *) func)->func != NULL);
59375
59376 /* [ ... func this | arg1 ... argN ] ('this' must precede new bottom) */
59377
59378 /* For native calls must be NULL so we don't sync back */
59379 DUK_ASSERT(thr->ptr_curr_pc == NULL);
59380
59381 if (func) {
59382 rc = ((duk_hnatfunc *) func)->func((duk_context *) thr);
59383 } else {
59384 duk_c_function funcptr = DUK_TVAL_GET_LIGHTFUNC_FUNCPTR(tv_func);
59385 rc = funcptr((duk_context *) thr);
59386 }
59387
59388 /* Automatic error throwing, retval check. */
59389
59390 if (rc < 0) {
59391 duk_error_throw_from_negative_rc(thr, rc);
59392 DUK_UNREACHABLE();
59393 } else if (rc > 1) {
59394 DUK_ERROR_TYPE(thr, "c function returned invalid rc");
59395 }
59396 DUK_ASSERT(rc == 0 || rc == 1);
59397
59398 /* Unwind. */
59399
59400 DUK_ASSERT(thr->catchstack_top == entry_catchstack_top); /* no need to unwind */
59401 DUK_ASSERT(thr->callstack_top == entry_callstack_top + 1);
59402 duk_hthread_callstack_unwind(thr, entry_callstack_top);
59403 duk_hthread_callstack_shrink_check(thr);
59404
59405 thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
59406 /* keep current valstack_top */
59407 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
59408 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
59409 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
59410 DUK_ASSERT(thr->valstack_top - thr->valstack_bottom >= idx_func + 1);
59411
59412 /* Return value handling. */
59413
59414 /* XXX: should this happen in the callee's activation or after unwinding? */
59415 tv_ret = thr->valstack_bottom + idx_func;
59416 if (rc == 0) {
59417 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv_ret); /* side effects */
59418 } else {
59419 /* [ ... func this (crud) retval ] */
59420 tv_funret = thr->valstack_top - 1;
59421#if defined(DUK_USE_FASTINT)
59422 /* Explicit check for fastint downgrade. */
59423 DUK_TVAL_CHKFAST_INPLACE_FAST(tv_funret);
59424#endif
59425 DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, tv_funret); /* side effects */
59426 }
59427 }
59428
59429 duk_set_top(ctx, idx_func + 1); /* XXX: unnecessary, handle in adjust */
59430
59431 /* [ ... retval ] */
59432
59433 /* Ensure there is internal valstack spare before we exit; this may
59434 * throw an alloc error. The same guaranteed size must be available
59435 * as before the call. This is not optimal now: we store the valstack
59436 * allocated size during entry; this value may be higher than the
59437 * minimal guarantee for an application.
59438 */
59439
59440 /* XXX: we should never shrink here; when we error out later, we'd
59441 * need to potentially grow the value stack in error unwind which could
59442 * cause another error.
59443 */
59444
59445 (void) duk_valstack_resize_raw((duk_context *) thr,
59446 entry_valstack_end, /* same as during entry */
59447 DUK_VSRESIZE_FLAG_SHRINK | /* flags */
59448 DUK_VSRESIZE_FLAG_COMPACT |
59449 DUK_VSRESIZE_FLAG_THROW);
59450
59451 /* Restore entry thread executor curr_pc stack frame pointer. */
59452 thr->ptr_curr_pc = entry_ptr_curr_pc;
59453
59454 DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */
59455 thr->state = (duk_uint8_t) entry_thread_state;
59456
59457 DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */
59458 (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */
59459 (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */
59460
59461 thr->heap->call_recursion_depth = entry_call_recursion_depth;
59462
59463 /* If the debugger is active we need to force an interrupt so that
59464 * debugger breakpoints are rechecked. This is important for function
59465 * calls caused by side effects (e.g. when doing a DUK_OP_GETPROP), see
59466 * GH-303. Only needed for success path, error path always causes a
59467 * breakpoint recheck in the executor. It would be enough to set this
59468 * only when returning to an Ecmascript activation, but setting the flag
59469 * on every return should have no ill effect.
59470 */
59471#if defined(DUK_USE_DEBUGGER_SUPPORT)
59472 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
59473 DUK_DD(DUK_DDPRINT("returning with debugger enabled, force interrupt"));
59474 DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init);
59475 thr->interrupt_init -= thr->interrupt_counter;
59476 thr->interrupt_counter = 0;
59477 thr->heap->dbg_force_restart = 1;
59478 }
59479#endif
59480
59481#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
59482 duk__interrupt_fixup(thr, entry_curr_thread);
59483#endif
59484
59485 return;
59486
59487 thread_state_error:
59488 DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "invalid thread state for call (%ld)", (long) thr->state);
59489 DUK_UNREACHABLE();
59490 return; /* never executed */
59491}
59492
59493DUK_LOCAL void duk__handle_call_error(duk_hthread *thr,
59494 duk_size_t entry_valstack_bottom_index,
59495 duk_size_t entry_valstack_end,
59496 duk_size_t entry_catchstack_top,
59497 duk_size_t entry_callstack_top,
59498 duk_int_t entry_call_recursion_depth,
59499 duk_hthread *entry_curr_thread,
59500 duk_uint_fast8_t entry_thread_state,
59501 duk_instr_t **entry_ptr_curr_pc,
59502 duk_idx_t idx_func,
59503 duk_jmpbuf *old_jmpbuf_ptr) {
59504 duk_context *ctx;
59505 duk_tval *tv_ret;
59506
59507 ctx = (duk_context *) thr;
59508
59509 DUK_DDD(DUK_DDDPRINT("error caught during duk__handle_call_inner(): %!T",
59510 (duk_tval *) &thr->heap->lj.value1));
59511
59512 /* Other longjmp types are handled by executor before propagating
59513 * the error here.
59514 */
59515 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);
59516 DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
59517 DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
59518
59519 /* We don't need to sync back thr->ptr_curr_pc here because
59520 * the bytecode executor always has a setjmp catchpoint which
59521 * does that before errors propagate to here.
59522 */
59523 DUK_ASSERT(thr->ptr_curr_pc == NULL);
59524
59525 /* Restore the previous setjmp catcher so that any error in
59526 * error handling will propagate outwards rather than re-enter
59527 * the same handler. However, the error handling path must be
59528 * designed to be error free so that sandboxing guarantees are
59529 * reliable, see e.g. https://github.com/svaarala/duktape/issues/476.
59530 */
59531 thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
59532
59533 /* XXX: callstack unwind may now throw an error when closing
59534 * scopes; this is a sandboxing issue, described in:
59535 * https://github.com/svaarala/duktape/issues/476
59536 */
59537 duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
59538 duk_hthread_catchstack_shrink_check(thr);
59539 duk_hthread_callstack_unwind(thr, entry_callstack_top);
59540 duk_hthread_callstack_shrink_check(thr);
59541
59542 thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
59543 tv_ret = thr->valstack_bottom + idx_func; /* XXX: byte offset? */
59544 DUK_TVAL_SET_TVAL_UPDREF(thr, tv_ret, &thr->heap->lj.value1); /* side effects */
59545#if defined(DUK_USE_FASTINT)
59546 /* Explicit check for fastint downgrade. */
59547 DUK_TVAL_CHKFAST_INPLACE_FAST(tv_ret);
59548#endif
59549 duk_set_top(ctx, idx_func + 1); /* XXX: could be eliminated with valstack adjust */
59550
59551 /* [ ... errobj ] */
59552
59553 /* Ensure there is internal valstack spare before we exit; this may
59554 * throw an alloc error. The same guaranteed size must be available
59555 * as before the call. This is not optimal now: we store the valstack
59556 * allocated size during entry; this value may be higher than the
59557 * minimal guarantee for an application.
59558 */
59559
59560 /* XXX: this needs to be reworked so that we never shrink the value
59561 * stack on function entry so that we never need to grow it here.
59562 * Needing to grow here is a sandboxing issue because we need to
59563 * allocate which may cause an error in the error handling path
59564 * and thus propagate an error out of a protected call.
59565 */
59566
59567 (void) duk_valstack_resize_raw((duk_context *) thr,
59568 entry_valstack_end, /* same as during entry */
59569 DUK_VSRESIZE_FLAG_SHRINK | /* flags */
59570 DUK_VSRESIZE_FLAG_COMPACT |
59571 DUK_VSRESIZE_FLAG_THROW);
59572
59573
59574 /* These are just convenience "wiping" of state. Side effects should
59575 * not be an issue here: thr->heap and thr->heap->lj have a stable
59576 * pointer. Finalizer runs etc capture even out-of-memory errors so
59577 * nothing should throw here.
59578 */
59579 thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
59580 thr->heap->lj.iserror = 0;
59581 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */
59582 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */
59583
59584 /* Restore entry thread executor curr_pc stack frame pointer. */
59585 thr->ptr_curr_pc = entry_ptr_curr_pc;
59586
59587 DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */
59588 thr->state = (duk_uint8_t) entry_thread_state;
59589
59590 DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */
59591 (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */
59592 (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */
59593
59594 thr->heap->call_recursion_depth = entry_call_recursion_depth;
59595
59596 /* If the debugger is active we need to force an interrupt so that
59597 * debugger breakpoints are rechecked. This is important for function
59598 * calls caused by side effects (e.g. when doing a DUK_OP_GETPROP), see
59599 * GH-303. Only needed for success path, error path always causes a
59600 * breakpoint recheck in the executor. It would be enough to set this
59601 * only when returning to an Ecmascript activation, but setting the flag
59602 * on every return should have no ill effect.
59603 */
59604#if defined(DUK_USE_DEBUGGER_SUPPORT)
59605 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
59606 DUK_DD(DUK_DDPRINT("returning with debugger enabled, force interrupt"));
59607 DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init);
59608 thr->interrupt_init -= thr->interrupt_counter;
59609 thr->interrupt_counter = 0;
59610 thr->heap->dbg_force_restart = 1;
59611 }
59612#endif
59613
59614#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
59615 duk__interrupt_fixup(thr, entry_curr_thread);
59616#endif
59617}
59618
59619/*
59620 * duk_handle_safe_call(): make a "C protected call" within the
59621 * current activation.
59622 *
59623 * The allowed thread states for making a call are the same as for
59624 * duk_handle_call_xxx().
59625 *
59626 * Error handling is similar to duk_handle_call_xxx(); errors may be thrown
59627 * (and result in a fatal error) for insane arguments.
59628 */
59629
59630/* XXX: bump preventcount by one for the duration of this call? */
59631
59632DUK_INTERNAL duk_int_t duk_handle_safe_call(duk_hthread *thr,
59633 duk_safe_call_function func,
59634 void *udata,
59635 duk_idx_t num_stack_args,
59636 duk_idx_t num_stack_rets) {
59637 duk_context *ctx = (duk_context *) thr;
59638 duk_size_t entry_valstack_bottom_index;
59639 duk_size_t entry_callstack_top;
59640 duk_size_t entry_catchstack_top;
59641 duk_int_t entry_call_recursion_depth;
59642 duk_hthread *entry_curr_thread;
59643 duk_uint_fast8_t entry_thread_state;
59644 duk_instr_t **entry_ptr_curr_pc;
59645 duk_jmpbuf *old_jmpbuf_ptr = NULL;
59646 duk_jmpbuf our_jmpbuf;
59647 duk_idx_t idx_retbase;
59648 duk_int_t retval;
59649
59650 DUK_ASSERT(thr != NULL);
59651 DUK_ASSERT(ctx != NULL);
59652
59653 /* Note: careful with indices like '-x'; if 'x' is zero, it refers to bottom */
59654 entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
59655 entry_callstack_top = thr->callstack_top;
59656 entry_catchstack_top = thr->catchstack_top;
59657 entry_call_recursion_depth = thr->heap->call_recursion_depth;
59658 entry_curr_thread = thr->heap->curr_thread; /* Note: may be NULL if first call */
59659 entry_thread_state = thr->state;
59660 entry_ptr_curr_pc = thr->ptr_curr_pc; /* may be NULL */
59661 idx_retbase = duk_get_top(ctx) - num_stack_args; /* Note: not a valid stack index if num_stack_args == 0 */
59662
59663 /* Note: cannot portably debug print a function pointer, hence 'func' not printed! */
59664 DUK_DD(DUK_DDPRINT("duk_handle_safe_call: thr=%p, num_stack_args=%ld, num_stack_rets=%ld, "
59665 "valstack_top=%ld, idx_retbase=%ld, rec_depth=%ld/%ld, "
59666 "entry_valstack_bottom_index=%ld, entry_callstack_top=%ld, entry_catchstack_top=%ld, "
59667 "entry_call_recursion_depth=%ld, entry_curr_thread=%p, entry_thread_state=%ld",
59668 (void *) thr,
59669 (long) num_stack_args,
59670 (long) num_stack_rets,
59671 (long) duk_get_top(ctx),
59672 (long) idx_retbase,
59673 (long) thr->heap->call_recursion_depth,
59674 (long) thr->heap->call_recursion_limit,
59675 (long) entry_valstack_bottom_index,
59676 (long) entry_callstack_top,
59677 (long) entry_catchstack_top,
59678 (long) entry_call_recursion_depth,
59679 (void *) entry_curr_thread,
59680 (long) entry_thread_state));
59681
59682 if (idx_retbase < 0) {
59683 /* Since stack indices are not reliable, we can't do anything useful
59684 * here. Invoke the existing setjmp catcher, or if it doesn't exist,
59685 * call the fatal error handler.
59686 */
59687
59688 DUK_ERROR_TYPE_INVALID_ARGS(thr);
59689 }
59690
59691 /* setjmp catchpoint setup */
59692
59693 old_jmpbuf_ptr = thr->heap->lj.jmpbuf_ptr;
59694 thr->heap->lj.jmpbuf_ptr = &our_jmpbuf;
59695
59696#if defined(DUK_USE_CPP_EXCEPTIONS)
59697 try {
59698#else
59699 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == &our_jmpbuf);
59700 if (DUK_SETJMP(our_jmpbuf.jb) == 0) {
59701 /* Success path. */
59702#endif
59703 DUK_DDD(DUK_DDDPRINT("safe_call setjmp catchpoint setup complete"));
59704
59705 duk__handle_safe_call_inner(thr,
59706 func,
59707 udata,
59708 idx_retbase,
59709 num_stack_rets,
59710 entry_valstack_bottom_index,
59711 entry_callstack_top,
59712 entry_catchstack_top);
59713
59714 /* Longjmp state is kept clean in success path */
59715 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
59716 DUK_ASSERT(thr->heap->lj.iserror == 0);
59717 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
59718 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
59719
59720 /* Note: either pointer may be NULL (at entry), so don't assert */
59721 thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
59722
59723 retval = DUK_EXEC_SUCCESS;
59724#if defined(DUK_USE_CPP_EXCEPTIONS)
59725 } catch (duk_internal_exception &exc) {
59726 DUK_UNREF(exc);
59727#else
59728 } else {
59729 /* Error path. */
59730#endif
59731 duk__handle_safe_call_error(thr,
59732 idx_retbase,
59733 num_stack_rets,
59734 entry_valstack_bottom_index,
59735 entry_callstack_top,
59736 entry_catchstack_top,
59737 old_jmpbuf_ptr);
59738
59739 /* Longjmp state is cleaned up by error handling */
59740 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_UNKNOWN);
59741 DUK_ASSERT(thr->heap->lj.iserror == 0);
59742 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value1));
59743 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(&thr->heap->lj.value2));
59744
59745 retval = DUK_EXEC_ERROR;
59746 }
59747#if defined(DUK_USE_CPP_EXCEPTIONS)
59748 catch (std::exception &exc) {
59749 const char *what = exc.what();
59750 if (!what) {
59751 what = "unknown";
59752 }
59753 DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
59754 try {
59755 DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
59756 } catch (duk_internal_exception exc) {
59757 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
59758 DUK_UNREF(exc);
59759 duk__handle_safe_call_error(thr,
59760 idx_retbase,
59761 num_stack_rets,
59762 entry_valstack_bottom_index,
59763 entry_callstack_top,
59764 entry_catchstack_top,
59765 old_jmpbuf_ptr);
59766 retval = DUK_EXEC_ERROR;
59767 }
59768 } catch (...) {
59769 DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
59770 try {
59771 DUK_ERROR_TYPE(thr, "caught invalid c++ exception (perhaps thrown by user code)");
59772 } catch (duk_internal_exception exc) {
59773 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
59774 DUK_UNREF(exc);
59775 duk__handle_safe_call_error(thr,
59776 idx_retbase,
59777 num_stack_rets,
59778 entry_valstack_bottom_index,
59779 entry_callstack_top,
59780 entry_catchstack_top,
59781 old_jmpbuf_ptr);
59782 retval = DUK_EXEC_ERROR;
59783 }
59784 }
59785#endif
59786
59787 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr == old_jmpbuf_ptr); /* success/error path both do this */
59788
59789 duk__handle_safe_call_shared(thr,
59790 idx_retbase,
59791 num_stack_rets,
59792 entry_call_recursion_depth,
59793 entry_curr_thread,
59794 entry_thread_state,
59795 entry_ptr_curr_pc);
59796
59797 return retval;
59798}
59799
59800DUK_LOCAL void duk__handle_safe_call_inner(duk_hthread *thr,
59801 duk_safe_call_function func,
59802 void *udata,
59803 duk_idx_t idx_retbase,
59804 duk_idx_t num_stack_rets,
59805 duk_size_t entry_valstack_bottom_index,
59806 duk_size_t entry_callstack_top,
59807 duk_size_t entry_catchstack_top) {
59808 duk_context *ctx;
59809 duk_ret_t rc;
59810
59811 DUK_ASSERT(thr != NULL);
59812 ctx = (duk_context *) thr;
59813 DUK_ASSERT_CTX_VALID(ctx);
59814 DUK_UNREF(entry_valstack_bottom_index);
59815 DUK_UNREF(entry_callstack_top);
59816 DUK_UNREF(entry_catchstack_top);
59817
59818 /*
59819 * Thread state check and book-keeping.
59820 */
59821
59822 if (thr == thr->heap->curr_thread) {
59823 /* same thread */
59824 if (thr->state != DUK_HTHREAD_STATE_RUNNING) {
59825 /* should actually never happen, but check anyway */
59826 goto thread_state_error;
59827 }
59828 } else {
59829 /* different thread */
59830 DUK_ASSERT(thr->heap->curr_thread == NULL ||
59831 thr->heap->curr_thread->state == DUK_HTHREAD_STATE_RUNNING);
59832 if (thr->state != DUK_HTHREAD_STATE_INACTIVE) {
59833 goto thread_state_error;
59834 }
59835 DUK_HEAP_SWITCH_THREAD(thr->heap, thr);
59836 thr->state = DUK_HTHREAD_STATE_RUNNING;
59837
59838 /* Note: multiple threads may be simultaneously in the RUNNING
59839 * state, but not in the same "resume chain".
59840 */
59841 }
59842
59843 DUK_ASSERT(thr->heap->curr_thread == thr);
59844 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
59845
59846 /*
59847 * Recursion limit check.
59848 *
59849 * Note: there is no need for an "ignore recursion limit" flag
59850 * for duk_handle_safe_call now.
59851 */
59852
59853 DUK_ASSERT(thr->heap->call_recursion_depth >= 0);
59854 DUK_ASSERT(thr->heap->call_recursion_depth <= thr->heap->call_recursion_limit);
59855 if (thr->heap->call_recursion_depth >= thr->heap->call_recursion_limit) {
59856 /* XXX: error message is a bit misleading: we reached a recursion
59857 * limit which is also essentially the same as a C callstack limit
59858 * (except perhaps with some relaxed threading assumptions).
59859 */
59860 DUK_ERROR_RANGE(thr, DUK_STR_C_CALLSTACK_LIMIT);
59861 }
59862 thr->heap->call_recursion_depth++;
59863
59864 /*
59865 * Valstack spare check
59866 */
59867
59868 duk_require_stack(ctx, 0); /* internal spare */
59869
59870 /*
59871 * Make the C call
59872 */
59873
59874 rc = func(ctx, udata);
59875
59876 DUK_DDD(DUK_DDDPRINT("safe_call, func rc=%ld", (long) rc));
59877
59878 /*
59879 * Valstack manipulation for results.
59880 */
59881
59882 /* we're running inside the caller's activation, so no change in call/catch stack or valstack bottom */
59883 DUK_ASSERT(thr->callstack_top == entry_callstack_top);
59884 DUK_ASSERT(thr->catchstack_top == entry_catchstack_top);
59885 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
59886 DUK_ASSERT((duk_size_t) (thr->valstack_bottom - thr->valstack) == entry_valstack_bottom_index);
59887 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
59888 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
59889
59890 if (rc < 0) {
59891 duk_error_throw_from_negative_rc(thr, rc);
59892 }
59893 DUK_ASSERT(rc >= 0);
59894
59895 if (duk_get_top(ctx) < rc) {
59896 DUK_ERROR_RANGE(thr, "not enough stack values for safe_call rc");
59897 }
59898
59899 DUK_ASSERT(thr->catchstack_top == entry_catchstack_top); /* no need to unwind */
59900 DUK_ASSERT(thr->callstack_top == entry_callstack_top);
59901
59902 duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, rc);
59903 return;
59904
59905 thread_state_error:
59906 DUK_ERROR_FMT1(thr, DUK_ERR_TYPE_ERROR, "invalid thread state for safe_call (%ld)", (long) thr->state);
59907 DUK_UNREACHABLE();
59908}
59909
59910DUK_LOCAL void duk__handle_safe_call_error(duk_hthread *thr,
59911 duk_idx_t idx_retbase,
59912 duk_idx_t num_stack_rets,
59913 duk_size_t entry_valstack_bottom_index,
59914 duk_size_t entry_callstack_top,
59915 duk_size_t entry_catchstack_top,
59916 duk_jmpbuf *old_jmpbuf_ptr) {
59917 duk_context *ctx;
59918
59919 DUK_ASSERT(thr != NULL);
59920 ctx = (duk_context *) thr;
59921 DUK_ASSERT_CTX_VALID(ctx);
59922
59923 /*
59924 * Error during call. The error value is at heap->lj.value1.
59925 *
59926 * The very first thing we do is restore the previous setjmp catcher.
59927 * This means that any error in error handling will propagate outwards
59928 * instead of causing a setjmp() re-entry above.
59929 */
59930
59931 DUK_DDD(DUK_DDDPRINT("error caught during protected duk_handle_safe_call()"));
59932
59933 /* Other longjmp types are handled by executor before propagating
59934 * the error here.
59935 */
59936 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW);
59937 DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
59938 DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
59939
59940 /* Note: either pointer may be NULL (at entry), so don't assert. */
59941 thr->heap->lj.jmpbuf_ptr = old_jmpbuf_ptr;
59942
59943 DUK_ASSERT(thr->catchstack_top >= entry_catchstack_top);
59944 DUK_ASSERT(thr->callstack_top >= entry_callstack_top);
59945 duk_hthread_catchstack_unwind(thr, entry_catchstack_top);
59946 duk_hthread_catchstack_shrink_check(thr);
59947 duk_hthread_callstack_unwind(thr, entry_callstack_top);
59948 duk_hthread_callstack_shrink_check(thr);
59949 thr->valstack_bottom = thr->valstack + entry_valstack_bottom_index;
59950
59951 /* [ ... | (crud) ] */
59952
59953 /* XXX: space in valstack? see discussion in duk_handle_call_xxx(). */
59954 duk_push_tval(ctx, &thr->heap->lj.value1);
59955
59956 /* [ ... | (crud) errobj ] */
59957
59958 DUK_ASSERT(duk_get_top(ctx) >= 1); /* at least errobj must be on stack */
59959
59960 /* check that the valstack has space for the final amount and any
59961 * intermediate space needed; this is unoptimal but should be safe
59962 */
59963 duk_require_stack_top(ctx, idx_retbase + num_stack_rets); /* final configuration */
59964 duk_require_stack(ctx, num_stack_rets);
59965
59966 duk__safe_call_adjust_valstack(thr, idx_retbase, num_stack_rets, 1); /* 1 = num actual 'return values' */
59967
59968 /* [ ... | ] or [ ... | errobj (M * undefined)] where M = num_stack_rets - 1 */
59969
59970 /* These are just convenience "wiping" of state. Side effects should
59971 * not be an issue here: thr->heap and thr->heap->lj have a stable
59972 * pointer. Finalizer runs etc capture even out-of-memory errors so
59973 * nothing should throw here.
59974 */
59975 thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
59976 thr->heap->lj.iserror = 0;
59977 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */
59978 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */
59979}
59980
59981DUK_LOCAL void duk__handle_safe_call_shared(duk_hthread *thr,
59982 duk_idx_t idx_retbase,
59983 duk_idx_t num_stack_rets,
59984 duk_int_t entry_call_recursion_depth,
59985 duk_hthread *entry_curr_thread,
59986 duk_uint_fast8_t entry_thread_state,
59987 duk_instr_t **entry_ptr_curr_pc) {
59988 duk_context *ctx;
59989
59990 DUK_ASSERT(thr != NULL);
59991 ctx = (duk_context *) thr;
59992 DUK_ASSERT_CTX_VALID(ctx);
59993 DUK_UNREF(ctx);
59994 DUK_UNREF(idx_retbase);
59995 DUK_UNREF(num_stack_rets);
59996
59997 /* Restore entry thread executor curr_pc stack frame pointer. */
59998 thr->ptr_curr_pc = entry_ptr_curr_pc;
59999
60000 /* XXX: because we unwind stacks above, thr->heap->curr_thread is at
60001 * risk of pointing to an already freed thread. This was indeed the
60002 * case in test-bug-multithread-valgrind.c, until duk_handle_call()
60003 * was fixed to restore thr->heap->curr_thread before rethrowing an
60004 * uncaught error.
60005 */
60006 DUK_HEAP_SWITCH_THREAD(thr->heap, entry_curr_thread); /* may be NULL */
60007 thr->state = (duk_uint8_t) entry_thread_state;
60008
60009 DUK_ASSERT((thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread == NULL) || /* first call */
60010 (thr->state == DUK_HTHREAD_STATE_INACTIVE && thr->heap->curr_thread != NULL) || /* other call */
60011 (thr->state == DUK_HTHREAD_STATE_RUNNING && thr->heap->curr_thread == thr)); /* current thread */
60012
60013 thr->heap->call_recursion_depth = entry_call_recursion_depth;
60014
60015 /* stack discipline consistency check */
60016 DUK_ASSERT(duk_get_top(ctx) == idx_retbase + num_stack_rets);
60017
60018 /* A debugger forced interrupt check is not needed here, as
60019 * problematic safe calls are not caused by side effects.
60020 */
60021
60022#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
60023 duk__interrupt_fixup(thr, entry_curr_thread);
60024#endif
60025}
60026
60027/*
60028 * Helper for handling an Ecmascript-to-Ecmascript call or an Ecmascript
60029 * function (initial) Duktape.Thread.resume().
60030 *
60031 * Compared to normal calls handled by duk_handle_call(), there are a
60032 * bunch of differences:
60033 *
60034 * - the call is never protected
60035 * - there is no C recursion depth increase (hence an "ignore recursion
60036 * limit" flag is not applicable)
60037 * - instead of making the call, this helper just performs the thread
60038 * setup and returns; the bytecode executor then restarts execution
60039 * internally
60040 * - ecmascript functions are never 'vararg' functions (they access
60041 * varargs through the 'arguments' object)
60042 *
60043 * The callstack of the target contains an earlier Ecmascript call in case
60044 * of an Ecmascript-to-Ecmascript call (whose idx_retval is updated), or
60045 * is empty in case of an initial Duktape.Thread.resume().
60046 *
60047 * The first thing to do here is to figure out whether an ecma-to-ecma
60048 * call is actually possible. It's not always the case if the target is
60049 * a bound function; the final function may be native. In that case,
60050 * return an error so caller can fall back to a normal call path.
60051 */
60052
60053DUK_INTERNAL duk_bool_t duk_handle_ecma_call_setup(duk_hthread *thr,
60054 duk_idx_t num_stack_args,
60055 duk_small_uint_t call_flags) {
60056 duk_context *ctx = (duk_context *) thr;
60057 duk_size_t entry_valstack_bottom_index;
60058 duk_idx_t idx_func; /* valstack index of 'func' and retval (relative to entry valstack_bottom) */
60059 duk_idx_t idx_args; /* valstack index of start of args (arg1) (relative to entry valstack_bottom) */
60060 duk_idx_t nargs; /* # argument registers target function wants (< 0 => never for ecma calls) */
60061 duk_idx_t nregs; /* # total registers target function wants on entry (< 0 => never for ecma calls) */
60062 duk_hobject *func; /* 'func' on stack (borrowed reference) */
60063 duk_tval *tv_func; /* duk_tval ptr for 'func' on stack (borrowed reference) */
60064 duk_activation *act;
60065 duk_hobject *env;
60066 duk_bool_t use_tailcall;
60067 duk_instr_t **entry_ptr_curr_pc;
60068
60069 DUK_ASSERT(thr != NULL);
60070 DUK_ASSERT(ctx != NULL);
60071 DUK_ASSERT(!((call_flags & DUK_CALL_FLAG_IS_RESUME) != 0 && (call_flags & DUK_CALL_FLAG_IS_TAILCALL) != 0));
60072
60073 /* XXX: assume these? */
60074 DUK_ASSERT(thr->valstack != NULL);
60075 DUK_ASSERT(thr->callstack != NULL);
60076 DUK_ASSERT(thr->catchstack != NULL);
60077
60078 /* no need to handle thread state book-keeping here */
60079 DUK_ASSERT((call_flags & DUK_CALL_FLAG_IS_RESUME) != 0 ||
60080 (thr->state == DUK_HTHREAD_STATE_RUNNING &&
60081 thr->heap->curr_thread == thr));
60082
60083 /* If thr->ptr_curr_pc is set, sync curr_pc to act->pc. Then NULL
60084 * thr->ptr_curr_pc so that it's not accidentally used with an incorrect
60085 * activation when side effects occur. If we end up not making the
60086 * call we must restore the value.
60087 */
60088 entry_ptr_curr_pc = thr->ptr_curr_pc;
60089 duk_hthread_sync_and_null_currpc(thr);
60090
60091 /* if a tail call:
60092 * - an Ecmascript activation must be on top of the callstack
60093 * - there cannot be any active catchstack entries
60094 */
60095#if defined(DUK_USE_ASSERTIONS)
60096 if (call_flags & DUK_CALL_FLAG_IS_TAILCALL) {
60097 duk_size_t our_callstack_index;
60098 duk_size_t i;
60099
60100 DUK_ASSERT(thr->callstack_top >= 1);
60101 our_callstack_index = thr->callstack_top - 1;
60102 DUK_ASSERT_DISABLE(our_callstack_index >= 0);
60103 DUK_ASSERT(our_callstack_index < thr->callstack_size);
60104 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + our_callstack_index) != NULL);
60105 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + our_callstack_index)));
60106
60107 /* No entry in the catchstack which would actually catch a
60108 * throw can refer to the callstack entry being reused.
60109 * There *can* be catchstack entries referring to the current
60110 * callstack entry as long as they don't catch (e.g. label sites).
60111 */
60112
60113 for (i = 0; i < thr->catchstack_top; i++) {
60114 DUK_ASSERT(thr->catchstack[i].callstack_index < our_callstack_index || /* refer to callstack entries below current */
60115 DUK_CAT_GET_TYPE(thr->catchstack + i) == DUK_CAT_TYPE_LABEL); /* or a non-catching entry */
60116 }
60117 }
60118#endif /* DUK_USE_ASSERTIONS */
60119
60120 entry_valstack_bottom_index = (duk_size_t) (thr->valstack_bottom - thr->valstack);
60121 /* XXX: rework */
60122 idx_func = duk_normalize_index(thr, -num_stack_args - 2);
60123 idx_args = idx_func + 2;
60124
60125 DUK_DD(DUK_DDPRINT("handle_ecma_call_setup: thr=%p, "
60126 "num_stack_args=%ld, call_flags=0x%08lx (resume=%ld, tailcall=%ld), "
60127 "idx_func=%ld, idx_args=%ld, entry_valstack_bottom_index=%ld",
60128 (void *) thr,
60129 (long) num_stack_args,
60130 (unsigned long) call_flags,
60131 (long) ((call_flags & DUK_CALL_FLAG_IS_RESUME) != 0 ? 1 : 0),
60132 (long) ((call_flags & DUK_CALL_FLAG_IS_TAILCALL) != 0 ? 1 : 0),
60133 (long) idx_func,
60134 (long) idx_args,
60135 (long) entry_valstack_bottom_index));
60136
60137 if (DUK_UNLIKELY(idx_func < 0 || idx_args < 0)) {
60138 /* XXX: assert? compiler is responsible for this never happening */
60139 DUK_ERROR_TYPE_INVALID_ARGS(thr);
60140 }
60141
60142 /*
60143 * Check the function type, handle bound function chains, and prepare
60144 * parameters for the rest of the call handling. Also figure out the
60145 * effective 'this' binding, which replaces the current value at
60146 * idx_func + 1.
60147 *
60148 * If the target function is a 'bound' one, follow the chain of 'bound'
60149 * functions until a non-bound function is found. During this process,
60150 * bound arguments are 'prepended' to existing ones, and the "this"
60151 * binding is overridden. See E5 Section 15.3.4.5.1.
60152 *
60153 * If the final target function cannot be handled by an ecma-to-ecma
60154 * call, return to the caller with a return value indicating this case.
60155 * The bound chain is resolved and the caller can resume with a plain
60156 * function call.
60157 */
60158
60159 func = duk__nonbound_func_lookup(ctx, idx_func, &num_stack_args, &tv_func, call_flags);
60160 if (func == NULL || !DUK_HOBJECT_IS_COMPFUNC(func)) {
60161 DUK_DDD(DUK_DDDPRINT("final target is a lightfunc/nativefunc, cannot do ecma-to-ecma call"));
60162 thr->ptr_curr_pc = entry_ptr_curr_pc;
60163 return 0;
60164 }
60165 /* XXX: tv_func is not actually needed */
60166
60167 DUK_ASSERT(func != NULL);
60168 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func));
60169 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(func));
60170
60171 duk__coerce_effective_this_binding(thr, func, idx_func + 1);
60172 DUK_DDD(DUK_DDDPRINT("effective 'this' binding is: %!T",
60173 duk_get_tval(ctx, idx_func + 1)));
60174
60175 nargs = ((duk_hcompfunc *) func)->nargs;
60176 nregs = ((duk_hcompfunc *) func)->nregs;
60177 DUK_ASSERT(nregs >= nargs);
60178
60179 /* [ ... func this arg1 ... argN ] */
60180
60181 /*
60182 * Preliminary activation record and valstack manipulation.
60183 * The concrete actions depend on whether the we're dealing
60184 * with a tail call (reuse an existing activation), a resume,
60185 * or a normal call.
60186 *
60187 * The basic actions, in varying order, are:
60188 *
60189 * - Check stack size for call handling
60190 * - Grow call stack if necessary (non-tail-calls)
60191 * - Update current activation (idx_retval) if necessary
60192 * (non-tail, non-resume calls)
60193 * - Move start of args (idx_args) to valstack bottom
60194 * (tail calls)
60195 *
60196 * Don't touch valstack_bottom or valstack_top yet so that Duktape API
60197 * calls work normally.
60198 */
60199
60200 /* XXX: some overlapping code; cleanup */
60201 use_tailcall = call_flags & DUK_CALL_FLAG_IS_TAILCALL;
60202#if !defined(DUK_USE_TAILCALL)
60203 DUK_ASSERT(use_tailcall == 0); /* compiler ensures this */
60204#endif
60205 if (use_tailcall) {
60206 /* tailcall cannot be flagged to resume calls, and a
60207 * previous frame must exist
60208 */
60209 DUK_ASSERT(thr->callstack_top >= 1);
60210 DUK_ASSERT((call_flags & DUK_CALL_FLAG_IS_RESUME) == 0);
60211
60212 act = thr->callstack + thr->callstack_top - 1;
60213 if (act->flags & DUK_ACT_FLAG_PREVENT_YIELD) {
60214 /* See: test-bug-tailcall-preventyield-assert.c. */
60215 DUK_DDD(DUK_DDDPRINT("tail call prevented by current activation having DUK_ACT_FLAG_PREVENTYIELD"));
60216 use_tailcall = 0;
60217 } else if (DUK_HOBJECT_HAS_NOTAIL(func)) {
60218 DUK_D(DUK_DPRINT("tail call prevented by function having a notail flag"));
60219 use_tailcall = 0;
60220 }
60221 }
60222
60223 if (use_tailcall) {
60224 duk_tval *tv1, *tv2;
60225 duk_size_t cs_index;
60226 duk_int_t i_stk; /* must be signed for loop structure */
60227 duk_idx_t i_arg;
60228
60229 /*
60230 * Tailcall handling
60231 *
60232 * Although the callstack entry is reused, we need to explicitly unwind
60233 * the current activation (or simulate an unwind). In particular, the
60234 * current activation must be closed, otherwise something like
60235 * test-bug-reduce-judofyr.js results. Also catchstack needs be unwound
60236 * because there may be non-error-catching label entries in valid tail calls.
60237 */
60238
60239 DUK_DDD(DUK_DDDPRINT("is tail call, reusing activation at callstack top, at index %ld",
60240 (long) (thr->callstack_top - 1)));
60241
60242 /* 'act' already set above */
60243
60244 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func));
60245 DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(func));
60246 DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func));
60247 DUK_ASSERT((act->flags & DUK_ACT_FLAG_PREVENT_YIELD) == 0);
60248
60249 /* Unwind catchstack entries referring to the callstack entry we're reusing */
60250 cs_index = thr->callstack_top - 1;
60251 DUK_ASSERT(thr->catchstack_top <= DUK_INT_MAX); /* catchstack limits */
60252 for (i_stk = (duk_int_t) (thr->catchstack_top - 1); i_stk >= 0; i_stk--) {
60253 duk_catcher *cat = thr->catchstack + i_stk;
60254 if (cat->callstack_index != cs_index) {
60255 /* 'i' is the first entry we'll keep */
60256 break;
60257 }
60258 }
60259 duk_hthread_catchstack_unwind(thr, i_stk + 1);
60260
60261 /* Unwind the topmost callstack entry before reusing it */
60262 DUK_ASSERT(thr->callstack_top > 0);
60263 duk_hthread_callstack_unwind(thr, thr->callstack_top - 1);
60264
60265 /* Then reuse the unwound activation; callstack was not shrunk so there is always space */
60266 thr->callstack_top++;
60267 DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
60268 act = thr->callstack + thr->callstack_top - 1;
60269
60270 /* Start filling in the activation */
60271 act->func = func; /* don't want an intermediate exposed state with func == NULL */
60272#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
60273 act->prev_caller = NULL;
60274#endif
60275 DUK_ASSERT(func != NULL);
60276 DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func));
60277 /* don't want an intermediate exposed state with invalid pc */
60278 act->curr_pc = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) func);
60279#if defined(DUK_USE_DEBUGGER_SUPPORT)
60280 act->prev_line = 0;
60281#endif
60282 DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */
60283#if defined(DUK_USE_REFERENCE_COUNTING)
60284 DUK_HOBJECT_INCREF(thr, func);
60285 act = thr->callstack + thr->callstack_top - 1; /* side effects (currently none though) */
60286#endif
60287
60288#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
60289#if defined(DUK_USE_TAILCALL)
60290#error incorrect options: tail calls enabled with function caller property
60291#endif
60292 /* XXX: this doesn't actually work properly for tail calls, so
60293 * tail calls are disabled when DUK_USE_NONSTD_FUNC_CALLER_PROPERTY
60294 * is in use.
60295 */
60296 duk__update_func_caller_prop(thr, func);
60297 act = thr->callstack + thr->callstack_top - 1;
60298#endif
60299
60300 act->flags = (DUK_HOBJECT_HAS_STRICT(func) ?
60301 DUK_ACT_FLAG_STRICT | DUK_ACT_FLAG_TAILCALLED :
60302 DUK_ACT_FLAG_TAILCALLED);
60303
60304 DUK_ASSERT(DUK_ACT_GET_FUNC(act) == func); /* already updated */
60305 DUK_ASSERT(act->var_env == NULL); /* already NULLed (by unwind) */
60306 DUK_ASSERT(act->lex_env == NULL); /* already NULLed (by unwind) */
60307 act->idx_bottom = entry_valstack_bottom_index; /* tail call -> reuse current "frame" */
60308 DUK_ASSERT(nregs >= 0);
60309#if 0 /* topmost activation idx_retval is considered garbage, no need to init */
60310 act->idx_retval = 0;
60311#endif
60312
60313 /*
60314 * Manipulate valstack so that args are on the current bottom and the
60315 * previous caller's 'this' binding (which is the value preceding the
60316 * current bottom) is replaced with the new 'this' binding:
60317 *
60318 * [ ... this_old | (crud) func this_new arg1 ... argN ]
60319 * --> [ ... this_new | arg1 ... argN ]
60320 *
60321 * For tail calling to work properly, the valstack bottom must not grow
60322 * here; otherwise crud would accumulate on the valstack.
60323 */
60324
60325 tv1 = thr->valstack_bottom - 1;
60326 tv2 = thr->valstack_bottom + idx_func + 1;
60327 DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top); /* tv1 is -below- valstack_bottom */
60328 DUK_ASSERT(tv2 >= thr->valstack_bottom && tv2 < thr->valstack_top);
60329 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
60330
60331 for (i_arg = 0; i_arg < idx_args; i_arg++) {
60332 /* XXX: block removal API primitive */
60333 /* Note: 'func' is popped from valstack here, but it is
60334 * already reachable from the activation.
60335 */
60336 duk_remove(ctx, 0);
60337 }
60338 idx_func = 0; DUK_UNREF(idx_func); /* really 'not applicable' anymore, should not be referenced after this */
60339 idx_args = 0;
60340
60341 /* [ ... this_new | arg1 ... argN ] */
60342 } else {
60343 DUK_DDD(DUK_DDDPRINT("not a tail call, pushing a new activation to callstack, to index %ld",
60344 (long) (thr->callstack_top)));
60345
60346 duk_hthread_callstack_grow(thr);
60347
60348 if (call_flags & DUK_CALL_FLAG_IS_RESUME) {
60349 DUK_DDD(DUK_DDDPRINT("is resume -> no update to current activation (may not even exist)"));
60350 } else {
60351 DUK_DDD(DUK_DDDPRINT("update to current activation idx_retval"));
60352 DUK_ASSERT(thr->callstack_top < thr->callstack_size);
60353 DUK_ASSERT(thr->callstack_top >= 1);
60354 act = thr->callstack + thr->callstack_top - 1;
60355 DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
60356 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(act)));
60357 act->idx_retval = entry_valstack_bottom_index + idx_func;
60358 }
60359
60360 DUK_ASSERT(thr->callstack_top < thr->callstack_size);
60361 act = thr->callstack + thr->callstack_top;
60362 thr->callstack_top++;
60363 DUK_ASSERT(thr->callstack_top <= thr->callstack_size);
60364
60365 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func));
60366 DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(func));
60367 DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func));
60368
60369 act->flags = (DUK_HOBJECT_HAS_STRICT(func) ?
60370 DUK_ACT_FLAG_STRICT :
60371 0);
60372 act->func = func;
60373 act->var_env = NULL;
60374 act->lex_env = NULL;
60375#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
60376 act->prev_caller = NULL;
60377#endif
60378 DUK_ASSERT(func != NULL);
60379 DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(func));
60380 act->curr_pc = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) func);
60381#if defined(DUK_USE_DEBUGGER_SUPPORT)
60382 act->prev_line = 0;
60383#endif
60384 act->idx_bottom = entry_valstack_bottom_index + idx_args;
60385 DUK_ASSERT(nregs >= 0);
60386#if 0 /* topmost activation idx_retval is considered garbage, no need to init */
60387 act->idx_retval = 0;
60388#endif
60389 DUK_TVAL_SET_OBJECT(&act->tv_func, func); /* borrowed, no refcount */
60390
60391 DUK_HOBJECT_INCREF(thr, func); /* act->func */
60392
60393#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
60394 duk__update_func_caller_prop(thr, func);
60395 act = thr->callstack + thr->callstack_top - 1;
60396#endif
60397 }
60398
60399 /* [ ... func this arg1 ... argN ] (not tail call)
60400 * [ this | arg1 ... argN ] (tail call)
60401 *
60402 * idx_args updated to match
60403 */
60404
60405 /*
60406 * Environment record creation and 'arguments' object creation.
60407 * Named function expression name binding is handled by the
60408 * compiler; the compiled function's parent env will contain
60409 * the (immutable) binding already.
60410 *
60411 * Delayed creation (on demand) is handled in duk_js_var.c.
60412 */
60413
60414 /* XXX: unify handling with native call. */
60415
60416 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func)); /* bound function chain has already been resolved */
60417
60418 if (!DUK_HOBJECT_HAS_NEWENV(func)) {
60419 /* use existing env (e.g. for non-strict eval); cannot have
60420 * an own 'arguments' object (but can refer to the existing one)
60421 */
60422
60423 duk__handle_oldenv_for_call(thr, func, act);
60424
60425 DUK_ASSERT(act->lex_env != NULL);
60426 DUK_ASSERT(act->var_env != NULL);
60427 goto env_done;
60428 }
60429
60430 DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
60431
60432 if (!DUK_HOBJECT_HAS_CREATEARGS(func)) {
60433 /* no need to create environment record now; leave as NULL */
60434 DUK_ASSERT(act->lex_env == NULL);
60435 DUK_ASSERT(act->var_env == NULL);
60436 goto env_done;
60437 }
60438
60439 /* third arg: absolute index (to entire valstack) of idx_bottom of new activation */
60440 env = duk_create_activation_environment_record(thr, func, act->idx_bottom);
60441 DUK_ASSERT(env != NULL);
60442
60443 /* [ ... arg1 ... argN envobj ] */
60444
60445 /* original input stack before nargs/nregs handling must be
60446 * intact for 'arguments' object
60447 */
60448 DUK_ASSERT(DUK_HOBJECT_HAS_CREATEARGS(func));
60449 duk__handle_createargs_for_call(thr, func, env, num_stack_args);
60450
60451 /* [ ... arg1 ... argN envobj ] */
60452
60453 act = thr->callstack + thr->callstack_top - 1;
60454 act->lex_env = env;
60455 act->var_env = env;
60456 DUK_HOBJECT_INCREF(thr, act->lex_env);
60457 DUK_HOBJECT_INCREF(thr, act->var_env);
60458 duk_pop(ctx);
60459
60460 env_done:
60461 /* [ ... arg1 ... argN ] */
60462
60463 /*
60464 * Setup value stack: clamp to 'nargs', fill up to 'nregs'
60465 */
60466
60467 duk__adjust_valstack_and_top(thr,
60468 num_stack_args,
60469 idx_args,
60470 nregs,
60471 nargs,
60472 func);
60473
60474 /*
60475 * Shift to new valstack_bottom.
60476 */
60477
60478 thr->valstack_bottom = thr->valstack_bottom + idx_args;
60479 /* keep current valstack_top */
60480 DUK_ASSERT(thr->valstack_bottom >= thr->valstack);
60481 DUK_ASSERT(thr->valstack_top >= thr->valstack_bottom);
60482 DUK_ASSERT(thr->valstack_end >= thr->valstack_top);
60483
60484 /*
60485 * Return to bytecode executor, which will resume execution from
60486 * the topmost activation.
60487 */
60488
60489 return 1;
60490}
60491/*
60492 * Ecmascript compiler.
60493 *
60494 * Parses an input string and generates a function template result.
60495 * Compilation may happen in multiple contexts (global code, eval
60496 * code, function code).
60497 *
60498 * The parser uses a traditional top-down recursive parsing for the
60499 * statement level, and an operator precedence based top-down approach
60500 * for the expression level. The attempt is to minimize the C stack
60501 * depth. Bytecode is generated directly without an intermediate
60502 * representation (tree), at the cost of needing two (and sometimes
60503 * three) passes over each function.
60504 *
60505 * The top-down recursive parser functions are named "duk__parse_XXX".
60506 *
60507 * Recursion limits are in key functions to prevent arbitrary C recursion:
60508 * function body parsing, statement parsing, and expression parsing.
60509 *
60510 * See doc/compiler.rst for discussion on the design.
60511 *
60512 * A few typing notes:
60513 *
60514 * - duk_regconst_t: unsigned, no marker value for "none"
60515 * - duk_reg_t: signed, < 0 = none
60516 * - PC values: duk_int_t, negative values used as markers
60517 */
60518
60519/* #include duk_internal.h -> already included */
60520
60521/* If highest bit of a register number is set, it refers to a constant instead.
60522 * When interpreted as a signed value, this means const values are always
60523 * negative (when interpreted as two's complement). For example DUK__ISTEMP()
60524 * uses this approach to avoid an explicit DUK__ISREG() check (the condition is
60525 * logically "'x' is a register AND 'x' >= temp_first").
60526 */
60527#define DUK__CONST_MARKER DUK_REGCONST_CONST_MARKER
60528#define DUK__ISREG(x) (((x) & DUK__CONST_MARKER) == 0)
60529#define DUK__ISCONST(x) (((x) & DUK__CONST_MARKER) != 0)
60530#define DUK__REMOVECONST(x) ((x) & ~DUK__CONST_MARKER)
60531#define DUK__ISTEMP(comp_ctx,x) ((duk_int32_t) (x) >= (duk_int32_t) ((comp_ctx)->curr_func.temp_first)) /* Avoid DUK__ISREG() check by interpreting as negative value. */
60532#define DUK__GETTEMP(comp_ctx) ((comp_ctx)->curr_func.temp_next)
60533#define DUK__SETTEMP(comp_ctx,x) ((comp_ctx)->curr_func.temp_next = (x)) /* dangerous: must only lower (temp_max not updated) */
60534#define DUK__SETTEMP_CHECKMAX(comp_ctx,x) duk__settemp_checkmax((comp_ctx),(x))
60535#define DUK__ALLOCTEMP(comp_ctx) duk__alloctemp((comp_ctx))
60536#define DUK__ALLOCTEMPS(comp_ctx,count) duk__alloctemps((comp_ctx),(count))
60537
60538/* Init value set size for array and object literals. */
60539#define DUK__MAX_ARRAY_INIT_VALUES 20
60540#define DUK__MAX_OBJECT_INIT_PAIRS 10
60541
60542/* XXX: hack, remove when const lookup is not O(n) */
60543#define DUK__GETCONST_MAX_CONSTS_CHECK 256
60544
60545/* These limits are based on bytecode limits. Max temps is limited
60546 * by duk_hcompfunc nargs/nregs fields being 16 bits.
60547 */
60548#define DUK__MAX_CONSTS DUK_BC_BC_MAX
60549#define DUK__MAX_FUNCS DUK_BC_BC_MAX
60550#define DUK__MAX_TEMPS 0xffffL
60551
60552/* Initial bytecode size allocation. */
60553#if defined(DUK_USE_PREFER_SIZE)
60554#define DUK__BC_INITIAL_INSTS 16
60555#else
60556#define DUK__BC_INITIAL_INSTS 256
60557#endif
60558
60559#define DUK__RECURSION_INCREASE(comp_ctx,thr) do { \
60560 DUK_DDD(DUK_DDDPRINT("RECURSION INCREASE: %s:%ld", (const char *) DUK_FILE_MACRO, (long) DUK_LINE_MACRO)); \
60561 duk__recursion_increase((comp_ctx)); \
60562 } while (0)
60563
60564#define DUK__RECURSION_DECREASE(comp_ctx,thr) do { \
60565 DUK_DDD(DUK_DDDPRINT("RECURSION DECREASE: %s:%ld", (const char *) DUK_FILE_MACRO, (long) DUK_LINE_MACRO)); \
60566 duk__recursion_decrease((comp_ctx)); \
60567 } while (0)
60568
60569/* Value stack slot limits: these are quite approximate right now, and
60570 * because they overlap in control flow, some could be eliminated.
60571 */
60572#define DUK__COMPILE_ENTRY_SLOTS 8
60573#define DUK__FUNCTION_INIT_REQUIRE_SLOTS 16
60574#define DUK__FUNCTION_BODY_REQUIRE_SLOTS 16
60575#define DUK__PARSE_STATEMENTS_SLOTS 16
60576#define DUK__PARSE_EXPR_SLOTS 16
60577
60578/* Temporary structure used to pass a stack allocated region through
60579 * duk_safe_call().
60580 */
60581typedef struct {
60582 duk_small_uint_t flags;
60583 duk_compiler_ctx comp_ctx_alloc;
60584 duk_lexer_point lex_pt_alloc;
60586
60587/*
60588 * Prototypes
60589 */
60590
60591/* lexing */
60592DUK_LOCAL_DECL void duk__advance_helper(duk_compiler_ctx *comp_ctx, duk_small_int_t expect);
60593DUK_LOCAL_DECL void duk__advance_expect(duk_compiler_ctx *comp_ctx, duk_small_int_t expect);
60594DUK_LOCAL_DECL void duk__advance(duk_compiler_ctx *ctx);
60595
60596/* function helpers */
60597DUK_LOCAL_DECL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx);
60598DUK_LOCAL_DECL void duk__reset_func_for_pass2(duk_compiler_ctx *comp_ctx);
60599DUK_LOCAL_DECL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ctx, duk_reg_t *out_stmt_value_reg);
60600DUK_LOCAL_DECL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx);
60601DUK_LOCAL_DECL duk_int_t duk__cleanup_varmap(duk_compiler_ctx *comp_ctx);
60602
60603/* code emission */
60604DUK_LOCAL_DECL duk_int_t duk__get_current_pc(duk_compiler_ctx *comp_ctx);
60605DUK_LOCAL_DECL duk_compiler_instr *duk__get_instr_ptr(duk_compiler_ctx *comp_ctx, duk_int_t pc);
60606DUK_LOCAL_DECL void duk__emit(duk_compiler_ctx *comp_ctx, duk_instr_t ins);
60607DUK_LOCAL_DECL void duk__emit_op_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t op);
60608DUK_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);
60609DUK_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);
60610DUK_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);
60611#if 0 /* unused */
60612DUK_LOCAL_DECL void duk__emit_a(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t a);
60613#endif
60614DUK_LOCAL_DECL void duk__emit_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t b);
60615DUK_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);
60616DUK_LOCAL_DECL void duk__emit_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t bc);
60617DUK_LOCAL_DECL void duk__emit_abc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t abc);
60618DUK_LOCAL_DECL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val);
60619DUK_LOCAL_DECL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val);
60620DUK_LOCAL_DECL void duk__emit_jump(duk_compiler_ctx *comp_ctx, duk_int_t target_pc);
60621DUK_LOCAL_DECL duk_int_t duk__emit_jump_empty(duk_compiler_ctx *comp_ctx);
60622DUK_LOCAL_DECL void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc);
60623DUK_LOCAL_DECL void duk__patch_jump(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc, duk_int_t target_pc);
60624DUK_LOCAL_DECL void duk__patch_jump_here(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc);
60625DUK_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);
60626DUK_LOCAL_DECL void duk__emit_if_false_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst);
60627DUK_LOCAL_DECL void duk__emit_if_true_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst);
60628DUK_LOCAL_DECL void duk__emit_invalid(duk_compiler_ctx *comp_ctx);
60629
60630/* ivalue/ispec helpers */
60631DUK_LOCAL_DECL void duk__ivalue_regconst(duk_ivalue *x, duk_regconst_t regconst);
60632DUK_LOCAL_DECL void duk__ivalue_plain_fromstack(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
60633DUK_LOCAL_DECL void duk__ivalue_var_fromstack(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
60634DUK_LOCAL_DECL void duk__ivalue_var_hstring(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_hstring *h);
60635DUK_LOCAL_DECL void duk__copy_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *src, duk_ispec *dst);
60636DUK_LOCAL_DECL void duk__copy_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *src, duk_ivalue *dst);
60637DUK_LOCAL_DECL duk_reg_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_int_t num);
60638DUK_LOCAL_DECL duk_reg_t duk__alloctemp(duk_compiler_ctx *comp_ctx);
60639DUK_LOCAL_DECL void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, duk_reg_t temp_next);
60640DUK_LOCAL_DECL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx);
60641DUK_LOCAL_DECL
60642duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
60643 duk_ispec *x,
60644 duk_reg_t forced_reg,
60645 duk_small_uint_t flags);
60646DUK_LOCAL_DECL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, duk_reg_t forced_reg);
60647DUK_LOCAL_DECL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_reg_t forced_reg);
60648DUK_LOCAL_DECL void duk__ivalue_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
60649DUK_LOCAL_DECL void duk__ivalue_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
60650DUK_LOCAL_DECL
60651duk_regconst_t duk__ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx,
60652 duk_ivalue *x,
60653 duk_reg_t forced_reg,
60654 duk_small_uint_t flags);
60655DUK_LOCAL_DECL duk_reg_t duk__ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
60656#if 0 /* unused */
60657DUK_LOCAL_DECL duk_reg_t duk__ivalue_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
60658#endif
60659DUK_LOCAL_DECL void duk__ivalue_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_int_t forced_reg);
60660DUK_LOCAL_DECL duk_regconst_t duk__ivalue_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
60661DUK_LOCAL_DECL duk_regconst_t duk__ivalue_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x);
60662
60663/* identifier handling */
60664DUK_LOCAL_DECL duk_reg_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_ctx);
60665DUK_LOCAL_DECL duk_bool_t duk__lookup_lhs(duk_compiler_ctx *ctx, duk_reg_t *out_reg_varbind, duk_regconst_t *out_rc_varname);
60666
60667/* label handling */
60668DUK_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);
60669DUK_LOCAL_DECL void duk__update_label_flags(duk_compiler_ctx *comp_ctx, duk_int_t label_id, duk_small_uint_t flags);
60670DUK_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);
60671DUK_LOCAL_DECL void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, duk_int_t len);
60672
60673/* top-down expression parser */
60674DUK_LOCAL_DECL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
60675DUK_LOCAL_DECL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_ivalue *res);
60676DUK_LOCAL_DECL duk_small_uint_t duk__expr_lbp(duk_compiler_ctx *comp_ctx);
60677DUK_LOCAL_DECL duk_bool_t duk__expr_is_empty(duk_compiler_ctx *comp_ctx);
60678
60679/* exprtop is the top level variant which resets nud/led counts */
60680DUK_LOCAL_DECL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
60681DUK_LOCAL_DECL void duk__exprtop(duk_compiler_ctx *ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
60682
60683/* convenience helpers */
60684#if 0 /* unused */
60685DUK_LOCAL_DECL duk_reg_t duk__expr_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
60686#endif
60687#if 0 /* unused */
60688DUK_LOCAL_DECL duk_reg_t duk__expr_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
60689#endif
60690DUK_LOCAL_DECL void duk__expr_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_reg_t forced_reg);
60691DUK_LOCAL_DECL duk_regconst_t duk__expr_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
60692#if 0 /* unused */
60693DUK_LOCAL_DECL duk_regconst_t duk__expr_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
60694#endif
60695DUK_LOCAL_DECL void duk__expr_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
60696DUK_LOCAL_DECL void duk__expr_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
60697DUK_LOCAL_DECL duk_reg_t duk__exprtop_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
60698#if 0 /* unused */
60699DUK_LOCAL_DECL duk_reg_t duk__exprtop_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
60700#endif
60701DUK_LOCAL_DECL void duk__exprtop_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_reg_t forced_reg);
60702DUK_LOCAL_DECL duk_regconst_t duk__exprtop_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
60703#if 0 /* unused */
60704DUK_LOCAL_DECL void duk__exprtop_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags);
60705#endif
60706
60707/* expression parsing helpers */
60708DUK_LOCAL_DECL duk_int_t duk__parse_arguments(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
60709DUK_LOCAL_DECL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
60710DUK_LOCAL_DECL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
60711
60712/* statement parsing */
60713DUK_LOCAL_DECL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags, duk_reg_t *out_reg_varbind, duk_regconst_t *out_rc_varname);
60714DUK_LOCAL_DECL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags);
60715DUK_LOCAL_DECL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
60716DUK_LOCAL_DECL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
60717DUK_LOCAL_DECL void duk__parse_if_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
60718DUK_LOCAL_DECL void duk__parse_do_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
60719DUK_LOCAL_DECL void duk__parse_while_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site);
60720DUK_LOCAL_DECL void duk__parse_break_or_continue_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
60721DUK_LOCAL_DECL void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
60722DUK_LOCAL_DECL void duk__parse_throw_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
60723DUK_LOCAL_DECL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
60724DUK_LOCAL_DECL void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res);
60725DUK_LOCAL_DECL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_bool_t allow_source_elem);
60726DUK_LOCAL_DECL duk_int_t duk__stmt_label_site(duk_compiler_ctx *comp_ctx, duk_int_t label_id);
60727DUK_LOCAL_DECL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_source_elem, duk_bool_t expect_eof);
60728
60729DUK_LOCAL_DECL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expect_eof, duk_bool_t implicit_return_value, duk_small_int_t expect_token);
60730DUK_LOCAL_DECL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx);
60731DUK_LOCAL_DECL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags);
60732DUK_LOCAL_DECL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags);
60733
60734#define DUK__FUNC_FLAG_DECL (1 << 0) /* Parsing a function declaration. */
60735#define DUK__FUNC_FLAG_GETSET (1 << 1) /* Parsing an object literal getter/setter. */
60736#define DUK__FUNC_FLAG_METDEF (1 << 2) /* Parsing an object literal method definition shorthand. */
60737#define DUK__FUNC_FLAG_PUSHNAME_PASS1 (1 << 3) /* Push function name when creating template (first pass only). */
60738#define DUK__FUNC_FLAG_USE_PREVTOKEN (1 << 4) /* Use prev_token to start function parsing (workaround for object literal). */
60739
60740/*
60741 * Parser control values for tokens. The token table is ordered by the
60742 * DUK_TOK_XXX defines.
60743 *
60744 * The binding powers are for lbp() use (i.e. for use in led() context).
60745 * Binding powers are positive for typing convenience, and bits at the
60746 * top should be reserved for flags. Binding power step must be higher
60747 * than 1 so that binding power "lbp - 1" can be used for right associative
60748 * operators. Currently a step of 2 is used (which frees one more bit for
60749 * flags).
60750 */
60751
60752/* XXX: actually single step levels would work just fine, clean up */
60753
60754/* binding power "levels" (see doc/compiler.rst) */
60755#define DUK__BP_INVALID 0 /* always terminates led() */
60756#define DUK__BP_EOF 2
60757#define DUK__BP_CLOSING 4 /* token closes expression, e.g. ')', ']' */
60758#define DUK__BP_FOR_EXPR DUK__BP_CLOSING /* bp to use when parsing a top level Expression */
60759#define DUK__BP_COMMA 6
60760#define DUK__BP_ASSIGNMENT 8
60761#define DUK__BP_CONDITIONAL 10
60762#define DUK__BP_LOR 12
60763#define DUK__BP_LAND 14
60764#define DUK__BP_BOR 16
60765#define DUK__BP_BXOR 18
60766#define DUK__BP_BAND 20
60767#define DUK__BP_EQUALITY 22
60768#define DUK__BP_RELATIONAL 24
60769#define DUK__BP_SHIFT 26
60770#define DUK__BP_ADDITIVE 28
60771#define DUK__BP_MULTIPLICATIVE 30
60772#define DUK__BP_EXPONENTIATION 32
60773#define DUK__BP_POSTFIX 34
60774#define DUK__BP_CALL 36
60775#define DUK__BP_MEMBER 38
60776
60777#define DUK__TOKEN_LBP_BP_MASK 0x1f
60778#define DUK__TOKEN_LBP_FLAG_NO_REGEXP (1 << 5) /* regexp literal must not follow this token */
60779#define DUK__TOKEN_LBP_FLAG_TERMINATES (1 << 6) /* terminates expression; e.g. post-increment/-decrement */
60780#define DUK__TOKEN_LBP_FLAG_UNUSED (1 << 7) /* spare */
60781
60782#define DUK__TOKEN_LBP_GET_BP(x) ((duk_small_uint_t) (((x) & DUK__TOKEN_LBP_BP_MASK) * 2))
60783
60784#define DUK__MK_LBP(bp) ((bp) >> 1) /* bp is assumed to be even */
60785#define DUK__MK_LBP_FLAGS(bp,flags) (((bp) >> 1) | (flags))
60786
60787DUK_LOCAL const duk_uint8_t duk__token_lbp[] = {
60788 DUK__MK_LBP(DUK__BP_EOF), /* DUK_TOK_EOF */
60789 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_IDENTIFIER */
60790 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_BREAK */
60791 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CASE */
60792 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CATCH */
60793 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CONTINUE */
60794 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DEBUGGER */
60795 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DEFAULT */
60796 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DELETE */
60797 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_DO */
60798 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_ELSE */
60799 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_FINALLY */
60800 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_FOR */
60801 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_FUNCTION */
60802 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_IF */
60803 DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_IN */
60804 DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_INSTANCEOF */
60805 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_NEW */
60806 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_RETURN */
60807 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SWITCH */
60808 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_THIS */
60809 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_THROW */
60810 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_TRY */
60811 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_TYPEOF */
60812 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_VAR */
60813 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CONST */
60814 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_VOID */
60815 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_WHILE */
60816 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_WITH */
60817 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_CLASS */
60818 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_ENUM */
60819 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_EXPORT */
60820 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_EXTENDS */
60821 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_IMPORT */
60822 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SUPER */
60823 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_NULL */
60824 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_TRUE */
60825 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_FALSE */
60826 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_GET */
60827 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SET */
60828 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_IMPLEMENTS */
60829 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_INTERFACE */
60830 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_LET */
60831 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PACKAGE */
60832 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PRIVATE */
60833 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PROTECTED */
60834 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_PUBLIC */
60835 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_STATIC */
60836 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_YIELD */
60837 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_LCURLY */
60838 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_RCURLY */
60839 DUK__MK_LBP(DUK__BP_MEMBER), /* DUK_TOK_LBRACKET */
60840 DUK__MK_LBP_FLAGS(DUK__BP_CLOSING, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_RBRACKET */
60841 DUK__MK_LBP(DUK__BP_CALL), /* DUK_TOK_LPAREN */
60842 DUK__MK_LBP_FLAGS(DUK__BP_CLOSING, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_RPAREN */
60843 DUK__MK_LBP(DUK__BP_MEMBER), /* DUK_TOK_PERIOD */
60844 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_SEMICOLON */
60845 DUK__MK_LBP(DUK__BP_COMMA), /* DUK_TOK_COMMA */
60846 DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_LT */
60847 DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_GT */
60848 DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_LE */
60849 DUK__MK_LBP(DUK__BP_RELATIONAL), /* DUK_TOK_GE */
60850 DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_EQ */
60851 DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_NEQ */
60852 DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_SEQ */
60853 DUK__MK_LBP(DUK__BP_EQUALITY), /* DUK_TOK_SNEQ */
60854 DUK__MK_LBP(DUK__BP_ADDITIVE), /* DUK_TOK_ADD */
60855 DUK__MK_LBP(DUK__BP_ADDITIVE), /* DUK_TOK_SUB */
60856 DUK__MK_LBP(DUK__BP_MULTIPLICATIVE), /* DUK_TOK_MUL */
60857 DUK__MK_LBP(DUK__BP_MULTIPLICATIVE), /* DUK_TOK_DIV */
60858 DUK__MK_LBP(DUK__BP_MULTIPLICATIVE), /* DUK_TOK_MOD */
60859 DUK__MK_LBP(DUK__BP_EXPONENTIATION), /* DUK_TOK_EXP */
60860 DUK__MK_LBP(DUK__BP_POSTFIX), /* DUK_TOK_INCREMENT */
60861 DUK__MK_LBP(DUK__BP_POSTFIX), /* DUK_TOK_DECREMENT */
60862 DUK__MK_LBP(DUK__BP_SHIFT), /* DUK_TOK_ALSHIFT */
60863 DUK__MK_LBP(DUK__BP_SHIFT), /* DUK_TOK_ARSHIFT */
60864 DUK__MK_LBP(DUK__BP_SHIFT), /* DUK_TOK_RSHIFT */
60865 DUK__MK_LBP(DUK__BP_BAND), /* DUK_TOK_BAND */
60866 DUK__MK_LBP(DUK__BP_BOR), /* DUK_TOK_BOR */
60867 DUK__MK_LBP(DUK__BP_BXOR), /* DUK_TOK_BXOR */
60868 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_LNOT */
60869 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_BNOT */
60870 DUK__MK_LBP(DUK__BP_LAND), /* DUK_TOK_LAND */
60871 DUK__MK_LBP(DUK__BP_LOR), /* DUK_TOK_LOR */
60872 DUK__MK_LBP(DUK__BP_CONDITIONAL), /* DUK_TOK_QUESTION */
60873 DUK__MK_LBP(DUK__BP_INVALID), /* DUK_TOK_COLON */
60874 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_EQUALSIGN */
60875 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_ADD_EQ */
60876 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_SUB_EQ */
60877 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_MUL_EQ */
60878 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_DIV_EQ */
60879 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_MOD_EQ */
60880 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_EXP_EQ */
60881 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_ALSHIFT_EQ */
60882 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_ARSHIFT_EQ */
60883 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_RSHIFT_EQ */
60884 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_BAND_EQ */
60885 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_BOR_EQ */
60886 DUK__MK_LBP(DUK__BP_ASSIGNMENT), /* DUK_TOK_BXOR_EQ */
60887 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_NUMBER */
60888 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_STRING */
60889 DUK__MK_LBP_FLAGS(DUK__BP_INVALID, DUK__TOKEN_LBP_FLAG_NO_REGEXP), /* DUK_TOK_REGEXP */
60890};
60891
60892/*
60893 * Misc helpers
60894 */
60895
60896DUK_LOCAL void duk__recursion_increase(duk_compiler_ctx *comp_ctx) {
60897 DUK_ASSERT(comp_ctx != NULL);
60898 DUK_ASSERT(comp_ctx->recursion_depth >= 0);
60899 if (comp_ctx->recursion_depth >= comp_ctx->recursion_limit) {
60900 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_COMPILER_RECURSION_LIMIT);
60901 }
60902 comp_ctx->recursion_depth++;
60903}
60904
60905DUK_LOCAL void duk__recursion_decrease(duk_compiler_ctx *comp_ctx) {
60906 DUK_ASSERT(comp_ctx != NULL);
60907 DUK_ASSERT(comp_ctx->recursion_depth > 0);
60908 comp_ctx->recursion_depth--;
60909}
60910
60911DUK_LOCAL duk_bool_t duk__hstring_is_eval_or_arguments(duk_compiler_ctx *comp_ctx, duk_hstring *h) {
60912 DUK_UNREF(comp_ctx);
60913 DUK_ASSERT(h != NULL);
60914 return DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(h);
60915}
60916
60917DUK_LOCAL duk_bool_t duk__hstring_is_eval_or_arguments_in_strict_mode(duk_compiler_ctx *comp_ctx, duk_hstring *h) {
60918 DUK_ASSERT(h != NULL);
60919 return (comp_ctx->curr_func.is_strict &&
60920 DUK_HSTRING_HAS_EVAL_OR_ARGUMENTS(h));
60921}
60922
60923/*
60924 * Parser duk__advance() token eating functions
60925 */
60926
60927/* XXX: valstack handling is awkward. Add a valstack helper which
60928 * avoids dup():ing; valstack_copy(src, dst)?
60929 */
60930
60931DUK_LOCAL void duk__advance_helper(duk_compiler_ctx *comp_ctx, duk_small_int_t expect) {
60932 duk_hthread *thr = comp_ctx->thr;
60933 duk_context *ctx = (duk_context *) thr;
60934 duk_bool_t regexp;
60935
60936 DUK_ASSERT(comp_ctx->curr_token.t >= 0 && comp_ctx->curr_token.t <= DUK_TOK_MAXVAL); /* MAXVAL is inclusive */
60937
60938 /*
60939 * Use current token to decide whether a RegExp can follow.
60940 *
60941 * We can use either 't' or 't_nores'; the latter would not
60942 * recognize keywords. Some keywords can be followed by a
60943 * RegExp (e.g. "return"), so using 't' is better. This is
60944 * not trivial, see doc/compiler.rst.
60945 */
60946
60947 regexp = 1;
60948 if (duk__token_lbp[comp_ctx->curr_token.t] & DUK__TOKEN_LBP_FLAG_NO_REGEXP) {
60949 regexp = 0;
60950 }
60951 if (comp_ctx->curr_func.reject_regexp_in_adv) {
60952 comp_ctx->curr_func.reject_regexp_in_adv = 0;
60953 regexp = 0;
60954 }
60955
60956 if (expect >= 0 && comp_ctx->curr_token.t != expect) {
60957 DUK_D(DUK_DPRINT("parse error: expect=%ld, got=%ld",
60958 (long) expect, (long) comp_ctx->curr_token.t));
60959 DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR);
60960 }
60961
60962 /* make current token the previous; need to fiddle with valstack "backing store" */
60963 DUK_MEMCPY(&comp_ctx->prev_token, &comp_ctx->curr_token, sizeof(duk_token));
60964 duk_copy(ctx, comp_ctx->tok11_idx, comp_ctx->tok21_idx);
60965 duk_copy(ctx, comp_ctx->tok12_idx, comp_ctx->tok22_idx);
60966
60967 /* parse new token */
60968 duk_lexer_parse_js_input_element(&comp_ctx->lex,
60969 &comp_ctx->curr_token,
60970 comp_ctx->curr_func.is_strict,
60971 regexp);
60972
60973 DUK_DDD(DUK_DDDPRINT("advance: curr: tok=%ld/%ld,%ld,term=%ld,%!T,%!T "
60974 "prev: tok=%ld/%ld,%ld,term=%ld,%!T,%!T",
60975 (long) comp_ctx->curr_token.t,
60976 (long) comp_ctx->curr_token.t_nores,
60977 (long) comp_ctx->curr_token.start_line,
60978 (long) comp_ctx->curr_token.lineterm,
60979 (duk_tval *) duk_get_tval(ctx, comp_ctx->tok11_idx),
60980 (duk_tval *) duk_get_tval(ctx, comp_ctx->tok12_idx),
60981 (long) comp_ctx->prev_token.t,
60982 (long) comp_ctx->prev_token.t_nores,
60983 (long) comp_ctx->prev_token.start_line,
60984 (long) comp_ctx->prev_token.lineterm,
60985 (duk_tval *) duk_get_tval(ctx, comp_ctx->tok21_idx),
60986 (duk_tval *) duk_get_tval(ctx, comp_ctx->tok22_idx)));
60987}
60988
60989/* advance, expecting current token to be a specific token; parse next token in regexp context */
60990DUK_LOCAL void duk__advance_expect(duk_compiler_ctx *comp_ctx, duk_small_int_t expect) {
60991 duk__advance_helper(comp_ctx, expect);
60992}
60993
60994/* advance, whatever the current token is; parse next token in regexp context */
60995DUK_LOCAL void duk__advance(duk_compiler_ctx *comp_ctx) {
60996 duk__advance_helper(comp_ctx, -1);
60997}
60998
60999/*
61000 * Helpers for duk_compiler_func.
61001 */
61002
61003/* init function state: inits valstack allocations */
61004DUK_LOCAL void duk__init_func_valstack_slots(duk_compiler_ctx *comp_ctx) {
61005 duk_compiler_func *func = &comp_ctx->curr_func;
61006 duk_hthread *thr = comp_ctx->thr;
61007 duk_context *ctx = (duk_context *) thr;
61008 duk_idx_t entry_top;
61009
61010 entry_top = duk_get_top(ctx);
61011
61012 DUK_MEMZERO(func, sizeof(*func)); /* intentional overlap with earlier memzero */
61013#if defined(DUK_USE_EXPLICIT_NULL_INIT)
61014 func->h_name = NULL;
61015 func->h_consts = NULL;
61016 func->h_funcs = NULL;
61017 func->h_decls = NULL;
61018 func->h_labelnames = NULL;
61019 func->h_labelinfos = NULL;
61020 func->h_argnames = NULL;
61021 func->h_varmap = NULL;
61022#endif
61023
61024 duk_require_stack(ctx, DUK__FUNCTION_INIT_REQUIRE_SLOTS);
61025
61026 DUK_BW_INIT_PUSHBUF(thr, &func->bw_code, DUK__BC_INITIAL_INSTS * sizeof(duk_compiler_instr));
61027 /* code_idx = entry_top + 0 */
61028
61029 duk_push_array(ctx);
61030 func->consts_idx = entry_top + 1;
61031 func->h_consts = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 1);
61032 DUK_ASSERT(func->h_consts != NULL);
61033
61034 duk_push_array(ctx);
61035 func->funcs_idx = entry_top + 2;
61036 func->h_funcs = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 2);
61037 DUK_ASSERT(func->h_funcs != NULL);
61038 DUK_ASSERT(func->fnum_next == 0);
61039
61040 duk_push_array(ctx);
61041 func->decls_idx = entry_top + 3;
61042 func->h_decls = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 3);
61043 DUK_ASSERT(func->h_decls != NULL);
61044
61045 duk_push_array(ctx);
61046 func->labelnames_idx = entry_top + 4;
61047 func->h_labelnames = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 4);
61048 DUK_ASSERT(func->h_labelnames != NULL);
61049
61050 duk_push_dynamic_buffer(ctx, 0);
61051 func->labelinfos_idx = entry_top + 5;
61052 func->h_labelinfos = (duk_hbuffer_dynamic *) duk_known_hbuffer(ctx, entry_top + 5);
61053 DUK_ASSERT(func->h_labelinfos != NULL);
61054 DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(func->h_labelinfos) && !DUK_HBUFFER_HAS_EXTERNAL(func->h_labelinfos));
61055
61056 duk_push_array(ctx);
61057 func->argnames_idx = entry_top + 6;
61058 func->h_argnames = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 6);
61059 DUK_ASSERT(func->h_argnames != NULL);
61060
61061 duk_push_bare_object(ctx);
61062 func->varmap_idx = entry_top + 7;
61063 func->h_varmap = DUK_GET_HOBJECT_POSIDX(ctx, entry_top + 7);
61064 DUK_ASSERT(func->h_varmap != NULL);
61065}
61066
61067/* reset function state (prepare for pass 2) */
61068DUK_LOCAL void duk__reset_func_for_pass2(duk_compiler_ctx *comp_ctx) {
61069 duk_compiler_func *func = &comp_ctx->curr_func;
61070 duk_hthread *thr = comp_ctx->thr;
61071 duk_context *ctx = (duk_context *) thr;
61072
61073 /* reset bytecode buffer but keep current size; pass 2 will
61074 * require same amount or more.
61075 */
61076 DUK_BW_RESET_SIZE(thr, &func->bw_code);
61077
61078 duk_set_length(ctx, func->consts_idx, 0);
61079 /* keep func->h_funcs; inner functions are not reparsed to avoid O(depth^2) parsing */
61080 func->fnum_next = 0;
61081 /* duk_set_length(ctx, func->funcs_idx, 0); */
61082 duk_set_length(ctx, func->labelnames_idx, 0);
61083 duk_hbuffer_reset(thr, func->h_labelinfos);
61084 /* keep func->h_argnames; it is fixed for all passes */
61085
61086 /* truncated in case pass 3 needed */
61087 duk_push_bare_object(ctx);
61088 duk_replace(ctx, func->varmap_idx);
61089 func->h_varmap = DUK_GET_HOBJECT_POSIDX(ctx, func->varmap_idx);
61090 DUK_ASSERT(func->h_varmap != NULL);
61091}
61092
61093/* cleanup varmap from any null entries, compact it, etc; returns number
61094 * of final entries after cleanup.
61095 */
61096DUK_LOCAL duk_int_t duk__cleanup_varmap(duk_compiler_ctx *comp_ctx) {
61097 duk_hthread *thr = comp_ctx->thr;
61098 duk_context *ctx = (duk_context *) thr;
61099 duk_hobject *h_varmap;
61100 duk_hstring *h_key;
61101 duk_tval *tv;
61102 duk_uint32_t i, e_next;
61103 duk_int_t ret;
61104
61105 /* [ ... varmap ] */
61106
61107 h_varmap = DUK_GET_HOBJECT_NEGIDX(ctx, -1);
61108 DUK_ASSERT(h_varmap != NULL);
61109
61110 ret = 0;
61111 e_next = DUK_HOBJECT_GET_ENEXT(h_varmap);
61112 for (i = 0; i < e_next; i++) {
61113 h_key = DUK_HOBJECT_E_GET_KEY(thr->heap, h_varmap, i);
61114 if (!h_key) {
61115 continue;
61116 }
61117
61118 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, h_varmap, i));
61119
61120 /* The entries can either be register numbers or 'null' values.
61121 * Thus, no need to DECREF them and get side effects. DECREF'ing
61122 * the keys (strings) can cause memory to be freed but no side
61123 * effects as strings don't have finalizers. This is why we can
61124 * rely on the object properties not changing from underneath us.
61125 */
61126
61127 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, h_varmap, i);
61128 if (!DUK_TVAL_IS_NUMBER(tv)) {
61129 DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv));
61130 DUK_HOBJECT_E_SET_KEY(thr->heap, h_varmap, i, NULL);
61131 DUK_HSTRING_DECREF(thr, h_key);
61132 /* when key is NULL, value is garbage so no need to set */
61133 } else {
61134 ret++;
61135 }
61136 }
61137
61138 duk_compact_m1(ctx);
61139
61140 return ret;
61141}
61142
61143/* Convert duk_compiler_func into a function template, leaving the result
61144 * on top of stack.
61145 */
61146/* XXX: awkward and bloated asm -- use faster internal accesses */
61147DUK_LOCAL void duk__convert_to_func_template(duk_compiler_ctx *comp_ctx) {
61148 duk_compiler_func *func = &comp_ctx->curr_func;
61149 duk_hthread *thr = comp_ctx->thr;
61150 duk_context *ctx = (duk_context *) thr;
61151 duk_hcompfunc *h_res;
61152 duk_hbuffer_fixed *h_data;
61153 duk_size_t consts_count;
61154 duk_size_t funcs_count;
61155 duk_size_t code_count;
61156 duk_size_t code_size;
61157 duk_size_t data_size;
61158 duk_size_t i;
61159 duk_tval *p_const;
61160 duk_hobject **p_func;
61161 duk_instr_t *p_instr;
61162 duk_compiler_instr *q_instr;
61163 duk_tval *tv;
61164 duk_bool_t keep_varmap;
61165 duk_bool_t keep_formals;
61166#if !defined(DUK_USE_DEBUGGER_SUPPORT)
61167 duk_size_t formals_length;
61168#endif
61169
61170 DUK_DDD(DUK_DDDPRINT("converting duk_compiler_func to function/template"));
61171
61172 /*
61173 * Push result object and init its flags
61174 */
61175
61176 /* Valstack should suffice here, required on function valstack init */
61177
61178 h_res = duk_push_hcompfunc(ctx);
61179 DUK_ASSERT(h_res != NULL);
61180 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) h_res) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
61181 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, (duk_hobject *) h_res, NULL); /* Function templates are "bare objects". */
61182
61183 if (func->is_function) {
61184 DUK_DDD(DUK_DDDPRINT("function -> set NEWENV"));
61185 DUK_HOBJECT_SET_NEWENV((duk_hobject *) h_res);
61186
61187 if (!func->is_arguments_shadowed) {
61188 /* arguments object would be accessible; note that shadowing
61189 * bindings are arguments or function declarations, neither
61190 * of which are deletable, so this is safe.
61191 */
61192
61193 if (func->id_access_arguments || func->may_direct_eval) {
61194 DUK_DDD(DUK_DDDPRINT("function may access 'arguments' object directly or "
61195 "indirectly -> set CREATEARGS"));
61196 DUK_HOBJECT_SET_CREATEARGS((duk_hobject *) h_res);
61197 }
61198 }
61199 } else if (func->is_eval && func->is_strict) {
61200 DUK_DDD(DUK_DDDPRINT("strict eval code -> set NEWENV"));
61201 DUK_HOBJECT_SET_NEWENV((duk_hobject *) h_res);
61202 } else {
61203 /* non-strict eval: env is caller's env or global env (direct vs. indirect call)
61204 * global code: env is is global env
61205 */
61206 DUK_DDD(DUK_DDDPRINT("non-strict eval code or global code -> no NEWENV"));
61207 DUK_ASSERT(!DUK_HOBJECT_HAS_NEWENV((duk_hobject *) h_res));
61208 }
61209
61210#if defined(DUK_USE_FUNC_NAME_PROPERTY)
61211 if (func->is_function && func->is_namebinding && func->h_name != NULL) {
61212 /* Object literal set/get functions have a name (property
61213 * name) but must not have a lexical name binding, see
61214 * test-bug-getset-func-name.js.
61215 */
61216 DUK_DDD(DUK_DDDPRINT("function expression with a name -> set NAMEBINDING"));
61217 DUK_HOBJECT_SET_NAMEBINDING((duk_hobject *) h_res);
61218 }
61219#endif
61220
61221 if (func->is_strict) {
61222 DUK_DDD(DUK_DDDPRINT("function is strict -> set STRICT"));
61223 DUK_HOBJECT_SET_STRICT((duk_hobject *) h_res);
61224 }
61225
61226 if (func->is_notail) {
61227 DUK_DDD(DUK_DDDPRINT("function is notail -> set NOTAIL"));
61228 DUK_HOBJECT_SET_NOTAIL((duk_hobject *) h_res);
61229 }
61230
61231 if (func->is_constructable) {
61232 DUK_DDD(DUK_DDDPRINT("function is constructable -> set CONSTRUCTABLE"));
61233 DUK_HOBJECT_SET_CONSTRUCTABLE((duk_hobject *) h_res);
61234 }
61235
61236 /*
61237 * Build function fixed size 'data' buffer, which contains bytecode,
61238 * constants, and inner function references.
61239 *
61240 * During the building phase 'data' is reachable but incomplete.
61241 * Only incref's occur during building (no refzero or GC happens),
61242 * so the building process is atomic.
61243 */
61244
61245 consts_count = duk_hobject_get_length(thr, func->h_consts);
61246 funcs_count = duk_hobject_get_length(thr, func->h_funcs) / 3;
61247 code_count = DUK_BW_GET_SIZE(thr, &func->bw_code) / sizeof(duk_compiler_instr);
61248 code_size = code_count * sizeof(duk_instr_t);
61249
61250 data_size = consts_count * sizeof(duk_tval) +
61251 funcs_count * sizeof(duk_hobject *) +
61252 code_size;
61253
61254 DUK_DDD(DUK_DDDPRINT("consts_count=%ld, funcs_count=%ld, code_size=%ld -> "
61255 "data_size=%ld*%ld + %ld*%ld + %ld = %ld",
61256 (long) consts_count, (long) funcs_count, (long) code_size,
61257 (long) consts_count, (long) sizeof(duk_tval),
61258 (long) funcs_count, (long) sizeof(duk_hobject *),
61259 (long) code_size, (long) data_size));
61260
61261 duk_push_fixed_buffer_nozero(ctx, data_size);
61262 h_data = (duk_hbuffer_fixed *) duk_known_hbuffer(ctx, -1);
61263
61264 DUK_HCOMPFUNC_SET_DATA(thr->heap, h_res, (duk_hbuffer *) h_data);
61265 DUK_HEAPHDR_INCREF(thr, h_data);
61266
61267 p_const = (duk_tval *) (void *) DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_data);
61268 for (i = 0; i < consts_count; i++) {
61269 DUK_ASSERT(i <= DUK_UARRIDX_MAX); /* const limits */
61270 tv = duk_hobject_find_existing_array_entry_tval_ptr(thr->heap, func->h_consts, (duk_uarridx_t) i);
61271 DUK_ASSERT(tv != NULL);
61272 DUK_TVAL_SET_TVAL(p_const, tv);
61273 p_const++;
61274 DUK_TVAL_INCREF(thr, tv); /* may be a string constant */
61275
61276 DUK_DDD(DUK_DDDPRINT("constant: %!T", (duk_tval *) tv));
61277 }
61278
61279 p_func = (duk_hobject **) p_const;
61280 DUK_HCOMPFUNC_SET_FUNCS(thr->heap, h_res, p_func);
61281 for (i = 0; i < funcs_count; i++) {
61282 duk_hobject *h;
61283 DUK_ASSERT(i * 3 <= DUK_UARRIDX_MAX); /* func limits */
61284 tv = duk_hobject_find_existing_array_entry_tval_ptr(thr->heap, func->h_funcs, (duk_uarridx_t) (i * 3));
61285 DUK_ASSERT(tv != NULL);
61286 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
61287 h = DUK_TVAL_GET_OBJECT(tv);
61288 DUK_ASSERT(h != NULL);
61289 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(h));
61290 *p_func++ = h;
61291 DUK_HOBJECT_INCREF(thr, h);
61292
61293 DUK_DDD(DUK_DDDPRINT("inner function: %p -> %!iO",
61294 (void *) h, (duk_heaphdr *) h));
61295 }
61296
61297 p_instr = (duk_instr_t *) p_func;
61298 DUK_HCOMPFUNC_SET_BYTECODE(thr->heap, h_res, p_instr);
61299
61300 /* copy bytecode instructions one at a time */
61301 q_instr = (duk_compiler_instr *) (void *) DUK_BW_GET_BASEPTR(thr, &func->bw_code);
61302 for (i = 0; i < code_count; i++) {
61303 p_instr[i] = q_instr[i].ins;
61304 }
61305 /* Note: 'q_instr' is still used below */
61306
61307 DUK_ASSERT((duk_uint8_t *) (p_instr + code_count) == DUK_HBUFFER_FIXED_GET_DATA_PTR(thr->heap, h_data) + data_size);
61308
61309 duk_pop(ctx); /* 'data' (and everything in it) is reachable through h_res now */
61310
61311 /*
61312 * Init non-property result fields
61313 *
61314 * 'nregs' controls how large a register frame is allocated.
61315 *
61316 * 'nargs' controls how many formal arguments are written to registers:
61317 * r0, ... r(nargs-1). The remaining registers are initialized to
61318 * undefined.
61319 */
61320
61321 DUK_ASSERT(func->temp_max >= 0);
61322 h_res->nregs = (duk_uint16_t) func->temp_max;
61323 h_res->nargs = (duk_uint16_t) duk_hobject_get_length(thr, func->h_argnames);
61324 DUK_ASSERT(h_res->nregs >= h_res->nargs); /* pass2 allocation handles this */
61325#if defined(DUK_USE_DEBUGGER_SUPPORT)
61326 h_res->start_line = (duk_uint32_t) func->min_line;
61327 h_res->end_line = (duk_uint32_t) func->max_line;
61328#endif
61329
61330 /*
61331 * Init object properties
61332 *
61333 * Properties should be added in decreasing order of access frequency.
61334 * (Not very critical for function templates.)
61335 */
61336
61337 DUK_DDD(DUK_DDDPRINT("init function properties"));
61338
61339 /* [ ... res ] */
61340
61341 /* _Varmap: omitted if function is guaranteed not to do a slow path
61342 * identifier access that might be caught by locally declared variables.
61343 * The varmap can also be omitted if it turns out empty of actual
61344 * register mappings after a cleanup. When debugging is enabled, we
61345 * always need the varmap to be able to lookup variables at any point.
61346 */
61347
61348#if defined(DUK_USE_DEBUGGER_SUPPORT)
61349 DUK_DD(DUK_DDPRINT("keeping _Varmap because debugger support is enabled"));
61350 keep_varmap = 1;
61351#else
61352 if (func->id_access_slow_own || /* directly uses slow accesses that may match own variables */
61353 func->id_access_arguments || /* accesses 'arguments' directly */
61354 func->may_direct_eval || /* may indirectly slow access through a direct eval */
61355 funcs_count > 0) { /* has inner functions which may slow access (XXX: this can be optimized by looking at the inner functions) */
61356 DUK_DD(DUK_DDPRINT("keeping _Varmap because of direct eval, slow path access that may match local variables, or presence of inner functions"));
61357 keep_varmap = 1;
61358 } else {
61359 DUK_DD(DUK_DDPRINT("dropping _Varmap"));
61360 keep_varmap = 0;
61361 }
61362#endif
61363
61364 if (keep_varmap) {
61365 duk_int_t num_used;
61366 duk_dup(ctx, func->varmap_idx);
61367 num_used = duk__cleanup_varmap(comp_ctx);
61368 DUK_DDD(DUK_DDDPRINT("cleaned up varmap: %!T (num_used=%ld)",
61369 (duk_tval *) duk_get_tval(ctx, -1), (long) num_used));
61370
61371 if (num_used > 0) {
61372 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_VARMAP, DUK_PROPDESC_FLAGS_NONE);
61373 } else {
61374 DUK_DD(DUK_DDPRINT("varmap is empty after cleanup -> no need to add"));
61375 duk_pop(ctx);
61376 }
61377 }
61378
61379 /* _Formals: omitted if function is guaranteed not to need a (non-strict)
61380 * arguments object, and _Formals.length matches nargs exactly.
61381 *
61382 * Non-arrow functions can't see an outer function's 'argument' binding
61383 * (because they have their own), but arrow functions can. When arrow
61384 * functions are added, this condition would need to be added:
61385 * inner_arrow_funcs_count > 0 inner arrow functions may access 'arguments'
61386 */
61387#if defined(DUK_USE_DEBUGGER_SUPPORT)
61388 DUK_DD(DUK_DDPRINT("keeping _Formals because debugger support is enabled"));
61389 keep_formals = 1;
61390#else
61391 formals_length = duk_get_length(ctx, func->argnames_idx);
61392 if (formals_length != (duk_size_t) h_res->nargs) {
61393 /* Nargs not enough for closure .length: keep _Formals regardless
61394 * of its length. Shouldn't happen in practice at the moment.
61395 */
61396 DUK_DD(DUK_DDPRINT("keeping _Formals because _Formals.length != nargs"));
61397 keep_formals = 1;
61398 } else if ((func->id_access_arguments || func->may_direct_eval) &&
61399 (formals_length > 0)) {
61400 /* Direct eval (may access 'arguments') or accesses 'arguments'
61401 * explicitly: keep _Formals unless it is zero length.
61402 */
61403 DUK_DD(DUK_DDPRINT("keeping _Formals because of direct eval or explicit access to 'arguments', and _Formals.length != 0"));
61404 keep_formals = 1;
61405 } else {
61406 DUK_DD(DUK_DDPRINT("omitting _Formals, nargs matches _Formals.length, so no properties added"));
61407 keep_formals = 0;
61408 }
61409#endif
61410
61411 if (keep_formals) {
61412 duk_dup(ctx, func->argnames_idx);
61413 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_FORMALS, DUK_PROPDESC_FLAGS_NONE);
61414 }
61415
61416 /* name */
61417#if defined(DUK_USE_FUNC_NAME_PROPERTY)
61418 if (func->h_name) {
61419 duk_push_hstring(ctx, func->h_name);
61420 DUK_DD(DUK_DDPRINT("setting function template .name to %!T", duk_get_tval(ctx, -1)));
61421 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_NONE);
61422 }
61423#endif /* DUK_USE_FUNC_NAME_PROPERTY */
61424
61425 /* _Source */
61426#if defined(DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY)
61427 if (0) {
61428 /* XXX: Currently function source code is not stored, as it is not
61429 * required by the standard. Source code should not be stored by
61430 * default (user should enable it explicitly), and the source should
61431 * probably be compressed with a trivial text compressor; average
61432 * compression of 20-30% is quite easy to achieve even with a trivial
61433 * compressor (RLE + backwards lookup).
61434 *
61435 * Debugging needs source code to be useful: sometimes input code is
61436 * not found in files as it may be generated and then eval()'d, given
61437 * by dynamic C code, etc.
61438 *
61439 * Other issues:
61440 *
61441 * - Need tokenizer indices for start and end to substring
61442 * - Always normalize function declaration part?
61443 * - If we keep _Formals, only need to store body
61444 */
61445
61446 /*
61447 * For global or eval code this is straightforward. For functions
61448 * created with the Function constructor we only get the source for
61449 * the body and must manufacture the "function ..." part.
61450 *
61451 * For instance, for constructed functions (v8):
61452 *
61453 * > a = new Function("foo", "bar", "print(foo)");
61454 * [Function]
61455 * > a.toString()
61456 * 'function anonymous(foo,bar) {\nprint(foo)\n}'
61457 *
61458 * Similarly for e.g. getters (v8):
61459 *
61460 * > x = { get a(foo,bar) { print(foo); } }
61461 * { a: [Getter] }
61462 * > Object.getOwnPropertyDescriptor(x, 'a').get.toString()
61463 * 'function a(foo,bar) { print(foo); }'
61464 */
61465
61466#if 0
61467 duk_push_string(ctx, "XXX");
61468 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_SOURCE, DUK_PROPDESC_FLAGS_NONE);
61469#endif
61470 }
61471#endif /* DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY */
61472
61473 /* _Pc2line */
61474#if defined(DUK_USE_PC2LINE)
61475 if (1) {
61476 /*
61477 * Size-optimized pc->line mapping.
61478 */
61479
61480 DUK_ASSERT(code_count <= DUK_COMPILER_MAX_BYTECODE_LENGTH);
61481 duk_hobject_pc2line_pack(thr, q_instr, (duk_uint_fast32_t) code_count); /* -> pushes fixed buffer */
61482 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_PC2LINE, DUK_PROPDESC_FLAGS_NONE);
61483
61484 /* XXX: if assertions enabled, walk through all valid PCs
61485 * and check line mapping.
61486 */
61487 }
61488#endif /* DUK_USE_PC2LINE */
61489
61490 /* fileName */
61491#if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
61492 if (comp_ctx->h_filename) {
61493 /*
61494 * Source filename (or equivalent), for identifying thrown errors.
61495 */
61496
61497 duk_push_hstring(ctx, comp_ctx->h_filename);
61498 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_FILE_NAME, DUK_PROPDESC_FLAGS_NONE);
61499 }
61500#endif
61501
61502 DUK_DD(DUK_DDPRINT("converted function: %!ixT",
61503 (duk_tval *) duk_get_tval(ctx, -1)));
61504
61505 /*
61506 * Compact the function template.
61507 */
61508
61509 duk_compact_m1(ctx);
61510
61511 /*
61512 * Debug dumping
61513 */
61514
61515#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
61516 {
61517 duk_hcompfunc *h;
61518 duk_instr_t *p, *p_start, *p_end;
61519
61520 h = (duk_hcompfunc *) duk_get_hobject(ctx, -1);
61521 p_start = (duk_instr_t *) DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, h);
61522 p_end = (duk_instr_t *) DUK_HCOMPFUNC_GET_CODE_END(thr->heap, h);
61523
61524 p = p_start;
61525 while (p < p_end) {
61526 DUK_DDD(DUK_DDDPRINT("BC %04ld: %!I ; 0x%08lx op=%ld (%!C) a=%ld b=%ld c=%ld",
61527 (long) (p - p_start),
61528 (duk_instr_t) (*p),
61529 (unsigned long) (*p),
61530 (long) DUK_DEC_OP(*p),
61531 (long) DUK_DEC_OP(*p),
61532 (long) DUK_DEC_A(*p),
61533 (long) DUK_DEC_B(*p),
61534 (long) DUK_DEC_C(*p)));
61535 p++;
61536 }
61537 }
61538#endif
61539}
61540
61541/*
61542 * Code emission helpers
61543 *
61544 * Some emission helpers understand the range of target and source reg/const
61545 * values and automatically emit shuffling code if necessary. This is the
61546 * case when the slot in question (A, B, C) is used in the standard way and
61547 * for opcodes the emission helpers explicitly understand (like DUK_OP_MPUTOBJ).
61548 *
61549 * The standard way is that:
61550 * - slot A is a target register
61551 * - slot B is a source register/constant
61552 * - slot C is a source register/constant
61553 *
61554 * If a slot is used in a non-standard way the caller must indicate this
61555 * somehow. If a slot is used as a target instead of a source (or vice
61556 * versa), this can be indicated with a flag to trigger proper shuffling
61557 * (e.g. DUK__EMIT_FLAG_B_IS_TARGET). If the value in the slot is not
61558 * register/const related at all, the caller must ensure that the raw value
61559 * fits into the corresponding slot so as to not trigger shuffling. The
61560 * caller must set a "no shuffle" flag to ensure compilation fails if
61561 * shuffling were to be triggered because of an internal error.
61562 *
61563 * For slots B and C the raw slot size is 9 bits but one bit is reserved for
61564 * the reg/const indicator. To use the full 9-bit range for a raw value,
61565 * shuffling must be disabled with the DUK__EMIT_FLAG_NO_SHUFFLE_{B,C} flag.
61566 * Shuffling is only done for A, B, and C slots, not the larger BC or ABC slots.
61567 *
61568 * There is call handling specific understanding in the A-B-C emitter to
61569 * convert call setup and call instructions into indirect ones if necessary.
61570 */
61571
61572/* Code emission flags, passed in the 'opcode' field. Opcode + flags
61573 * fit into 16 bits for now, so use duk_small_uint_t.
61574 */
61575#define DUK__EMIT_FLAG_NO_SHUFFLE_A (1 << 8)
61576#define DUK__EMIT_FLAG_NO_SHUFFLE_B (1 << 9)
61577#define DUK__EMIT_FLAG_NO_SHUFFLE_C (1 << 10)
61578#define DUK__EMIT_FLAG_A_IS_SOURCE (1 << 11) /* slot A is a source (default: target) */
61579#define DUK__EMIT_FLAG_B_IS_TARGET (1 << 12) /* slot B is a target (default: source) */
61580#define DUK__EMIT_FLAG_C_IS_TARGET (1 << 13) /* slot C is a target (default: source) */
61581#define DUK__EMIT_FLAG_BC_REGCONST (1 << 14) /* slots B and C are reg/const */
61582#define DUK__EMIT_FLAG_RESERVE_JUMPSLOT (1 << 15) /* reserve a jumpslot after instr before target spilling, used for NEXTENUM */
61583
61584/* XXX: macro smaller than call? */
61585DUK_LOCAL duk_int_t duk__get_current_pc(duk_compiler_ctx *comp_ctx) {
61586 duk_compiler_func *func;
61587 func = &comp_ctx->curr_func;
61588 return (duk_int_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &func->bw_code) / sizeof(duk_compiler_instr));
61589}
61590
61591DUK_LOCAL duk_compiler_instr *duk__get_instr_ptr(duk_compiler_ctx *comp_ctx, duk_int_t pc) {
61592 DUK_ASSERT(pc >= 0);
61593 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)));
61594 return ((duk_compiler_instr *) (void *) DUK_BW_GET_BASEPTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code)) + pc;
61595}
61596
61597/* emit instruction; could return PC but that's not needed in the majority
61598 * of cases.
61599 */
61600DUK_LOCAL void duk__emit(duk_compiler_ctx *comp_ctx, duk_instr_t ins) {
61601#if defined(DUK_USE_PC2LINE)
61602 duk_int_t line;
61603#endif
61604 duk_compiler_instr *instr;
61605
61606 DUK_DDD(DUK_DDDPRINT("duk__emit: 0x%08lx curr_token.start_line=%ld prev_token.start_line=%ld pc=%ld --> %!I",
61607 (unsigned long) ins,
61608 (long) comp_ctx->curr_token.start_line,
61609 (long) comp_ctx->prev_token.start_line,
61610 (long) duk__get_current_pc(comp_ctx),
61611 (duk_instr_t) ins));
61612
61613 instr = (duk_compiler_instr *) (void *) DUK_BW_ENSURE_GETPTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, sizeof(duk_compiler_instr));
61614 DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, sizeof(duk_compiler_instr));
61615
61616#if defined(DUK_USE_PC2LINE)
61617 /* The line number tracking is a bit inconsistent right now, which
61618 * affects debugger accuracy. Mostly call sites emit opcodes when
61619 * they have parsed a token (say a terminating semicolon) and called
61620 * duk__advance(). In this case the line number of the previous
61621 * token is the most accurate one (except in prologue where
61622 * prev_token.start_line is 0). This is probably not 100% correct
61623 * right now.
61624 */
61625 /* approximation, close enough */
61626 line = comp_ctx->prev_token.start_line;
61627 if (line == 0) {
61628 line = comp_ctx->curr_token.start_line;
61629 }
61630#endif
61631
61632 instr->ins = ins;
61633#if defined(DUK_USE_PC2LINE)
61634 instr->line = line;
61635#endif
61636#if defined(DUK_USE_DEBUGGER_SUPPORT)
61637 if (line < comp_ctx->curr_func.min_line) {
61638 comp_ctx->curr_func.min_line = line;
61639 }
61640 if (line > comp_ctx->curr_func.max_line) {
61641 comp_ctx->curr_func.max_line = line;
61642 }
61643#endif
61644
61645 /* Limit checks for bytecode byte size and line number. */
61646 if (DUK_UNLIKELY(DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) > DUK_USE_ESBC_MAX_BYTES)) {
61647 goto fail_bc_limit;
61648 }
61649#if defined(DUK_USE_PC2LINE) && defined(DUK_USE_ESBC_LIMITS)
61650#if defined(DUK_USE_BUFLEN16)
61651 /* Buffer length is bounded to 0xffff automatically, avoid compile warning. */
61652 if (DUK_UNLIKELY(line > DUK_USE_ESBC_MAX_LINENUMBER)) {
61653 goto fail_bc_limit;
61654 }
61655#else
61656 if (DUK_UNLIKELY(line > DUK_USE_ESBC_MAX_LINENUMBER)) {
61657 goto fail_bc_limit;
61658 }
61659#endif
61660#endif
61661
61662 return;
61663
61664 fail_bc_limit:
61665 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_BYTECODE_LIMIT);
61666}
61667
61668/* Update function min/max line from current token. Needed to improve
61669 * function line range information for debugging, so that e.g. opening
61670 * curly brace is covered by line range even when no opcodes are emitted
61671 * for the line containing the brace.
61672 */
61673DUK_LOCAL void duk__update_lineinfo_currtoken(duk_compiler_ctx *comp_ctx) {
61674#if defined(DUK_USE_DEBUGGER_SUPPORT)
61675 duk_int_t line;
61676
61677 line = comp_ctx->curr_token.start_line;
61678 if (line == 0) {
61679 return;
61680 }
61681 if (line < comp_ctx->curr_func.min_line) {
61682 comp_ctx->curr_func.min_line = line;
61683 }
61684 if (line > comp_ctx->curr_func.max_line) {
61685 comp_ctx->curr_func.max_line = line;
61686 }
61687#else
61688 DUK_UNREF(comp_ctx);
61689#endif
61690}
61691
61692DUK_LOCAL void duk__emit_op_only(duk_compiler_ctx *comp_ctx, duk_small_uint_t op) {
61693 duk__emit(comp_ctx, DUK_ENC_OP_ABC(op, 0));
61694}
61695
61696/* Important main primitive. */
61697DUK_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) {
61698 duk_instr_t ins = 0;
61699 duk_int_t a_out = -1;
61700 duk_int_t b_out = -1;
61701 duk_int_t c_out = -1;
61702 duk_int_t tmp;
61703 duk_small_int_t op = op_flags & 0xff;
61704
61705 DUK_DDD(DUK_DDDPRINT("emit: op_flags=%04lx, a=%ld, b=%ld, c=%ld",
61706 (unsigned long) op_flags, (long) a, (long) b, (long) c));
61707
61708 /* We could rely on max temp/const checks: if they don't exceed BC
61709 * limit, nothing here can either (just asserts would be enough).
61710 * Currently we check for the limits, which provides additional
61711 * protection against creating invalid bytecode due to compiler
61712 * bugs.
61713 */
61714
61715 DUK_ASSERT_DISABLE((op_flags & 0xff) >= DUK_BC_OP_MIN); /* unsigned */
61716 DUK_ASSERT((op_flags & 0xff) <= DUK_BC_OP_MAX);
61717
61718 /* Input shuffling happens before the actual operation, while output
61719 * shuffling happens afterwards. Output shuffling decisions are still
61720 * made at the same time to reduce branch clutter; output shuffle decisions
61721 * are recorded into X_out variables.
61722 */
61723
61724 /* Slot A: currently no support for reg/const. */
61725
61726#if defined(DUK_USE_SHUFFLE_TORTURE)
61727 if (a <= DUK_BC_A_MAX && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A)) {
61728#else
61729 if (a <= DUK_BC_A_MAX) {
61730#endif
61731 ;
61732 } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A) {
61733 DUK_D(DUK_DPRINT("out of regs: 'a' (reg) needs shuffling but shuffle prohibited, a: %ld", (long) a));
61734 goto error_outofregs;
61735 } else if (a <= DUK_BC_BC_MAX) {
61736 comp_ctx->curr_func.needs_shuffle = 1;
61737 tmp = comp_ctx->curr_func.shuffle1;
61738 if (op_flags & DUK__EMIT_FLAG_A_IS_SOURCE) {
61739 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, a));
61740 } else {
61741 /* Output shuffle needed after main operation */
61742 a_out = a;
61743
61744 /* The DUK_OP_CSVAR output shuffle assumes shuffle registers are
61745 * consecutive.
61746 */
61747 DUK_ASSERT((comp_ctx->curr_func.shuffle1 == 0 && comp_ctx->curr_func.shuffle2 == 0) ||
61748 comp_ctx->curr_func.shuffle2 == comp_ctx->curr_func.shuffle1 + 1);
61749 if (op == DUK_OP_CSVAR) {
61750 /* For CSVAR the limit is one smaller because output shuffle
61751 * must be able to express 'a + 1' in BC.
61752 */
61753 if (a + 1 > DUK_BC_BC_MAX) {
61754 goto error_outofregs;
61755 }
61756 }
61757 }
61758 a = tmp;
61759 } else {
61760 DUK_D(DUK_DPRINT("out of regs: 'a' (reg) needs shuffling but does not fit into BC, a: %ld", (long) a));
61761 goto error_outofregs;
61762 }
61763
61764 /* Slot B: reg/const support, mapped to bit 0 of opcode. */
61765
61766 if (b & DUK__CONST_MARKER) {
61767 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B) == 0);
61768 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_B_IS_TARGET) == 0);
61769 b = b & ~DUK__CONST_MARKER;
61770#if defined(DUK_USE_SHUFFLE_TORTURE)
61771 if (0) {
61772#else
61773 if (b <= 0xff) {
61774#endif
61775 if (op_flags & DUK__EMIT_FLAG_BC_REGCONST) {
61776 /* Opcode follows B/C reg/const convention. */
61777 DUK_ASSERT((op & 0x01) == 0);
61778 ins |= DUK_ENC_OP_A_B_C(0x01, 0, 0, 0); /* const flag for B */
61779 } else {
61780 DUK_D(DUK_DPRINT("B is const, opcode is not B/C reg/const: %x", op_flags));
61781 }
61782 } else if (b <= DUK_BC_BC_MAX) {
61783 comp_ctx->curr_func.needs_shuffle = 1;
61784 tmp = comp_ctx->curr_func.shuffle2;
61785 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDCONST, tmp, b));
61786 b = tmp;
61787 } else {
61788 DUK_D(DUK_DPRINT("out of regs: 'b' (const) needs shuffling but does not fit into BC, b: %ld", (long) b));
61789 goto error_outofregs;
61790 }
61791 } else {
61792#if defined(DUK_USE_SHUFFLE_TORTURE)
61793 if (b <= 0xff && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B)) {
61794#else
61795 if (b <= 0xff) {
61796#endif
61797 ;
61798 } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_B) {
61799 if (b > DUK_BC_B_MAX) {
61800 /* Note: 0xff != DUK_BC_B_MAX */
61801 DUK_D(DUK_DPRINT("out of regs: 'b' (reg) needs shuffling but shuffle prohibited, b: %ld", (long) b));
61802 goto error_outofregs;
61803 }
61804 } else if (b <= DUK_BC_BC_MAX) {
61805 comp_ctx->curr_func.needs_shuffle = 1;
61806 tmp = comp_ctx->curr_func.shuffle2;
61807 if (op_flags & DUK__EMIT_FLAG_B_IS_TARGET) {
61808 /* Output shuffle needed after main operation */
61809 b_out = b;
61810 }
61811 if (!(op_flags & DUK__EMIT_FLAG_B_IS_TARGET)) {
61812 if (op == DUK_OP_MPUTOBJ || op == DUK_OP_MPUTARR) {
61813 /* Special handling for MPUTOBJ/MPUTARR shuffling.
61814 * For each, slot B identifies the first register of a range
61815 * of registers, so normal shuffling won't work. Instead,
61816 * an indirect version of the opcode is used.
61817 */
61818 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_B_IS_TARGET) == 0);
61819 duk__emit_load_int32_noshuffle(comp_ctx, tmp, b);
61820 DUK_ASSERT(DUK_OP_MPUTOBJI == DUK_OP_MPUTOBJ + 1);
61821 DUK_ASSERT(DUK_OP_MPUTARRI == DUK_OP_MPUTARR + 1);
61822 op_flags++; /* indirect opcode follows direct */
61823 } else {
61824 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, b));
61825 }
61826 }
61827 b = tmp;
61828 } else {
61829 DUK_D(DUK_DPRINT("out of regs: 'b' (reg) needs shuffling but does not fit into BC, b: %ld", (long) b));
61830 goto error_outofregs;
61831 }
61832 }
61833
61834 /* Slot C: reg/const support, mapped to bit 1 of opcode. */
61835
61836 if (c & DUK__CONST_MARKER) {
61837 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C) == 0);
61838 DUK_ASSERT((op_flags & DUK__EMIT_FLAG_C_IS_TARGET) == 0);
61839 c = c & ~DUK__CONST_MARKER;
61840#if defined(DUK_USE_SHUFFLE_TORTURE)
61841 if (0) {
61842#else
61843 if (c <= 0xff) {
61844#endif
61845 if (op_flags & DUK__EMIT_FLAG_BC_REGCONST) {
61846 /* Opcode follows B/C reg/const convention. */
61847 DUK_ASSERT((op & 0x02) == 0);
61848 ins |= DUK_ENC_OP_A_B_C(0x02, 0, 0, 0); /* const flag for C */
61849 } else {
61850 DUK_D(DUK_DPRINT("C is const, opcode is not B/C reg/const: %x", op_flags));
61851 }
61852 } else if (c <= DUK_BC_BC_MAX) {
61853 comp_ctx->curr_func.needs_shuffle = 1;
61854 tmp = comp_ctx->curr_func.shuffle3;
61855 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDCONST, tmp, c));
61856 c = tmp;
61857 } else {
61858 DUK_D(DUK_DPRINT("out of regs: 'c' (const) needs shuffling but does not fit into BC, c: %ld", (long) c));
61859 goto error_outofregs;
61860 }
61861 } else {
61862#if defined(DUK_USE_SHUFFLE_TORTURE)
61863 if (c <= 0xff && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C)) {
61864#else
61865 if (c <= 0xff) {
61866#endif
61867 ;
61868 } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_C) {
61869 if (c > DUK_BC_C_MAX) {
61870 /* Note: 0xff != DUK_BC_C_MAX */
61871 DUK_D(DUK_DPRINT("out of regs: 'c' (reg) needs shuffling but shuffle prohibited, c: %ld", (long) c));
61872 goto error_outofregs;
61873 }
61874 } else if (c <= DUK_BC_BC_MAX) {
61875 comp_ctx->curr_func.needs_shuffle = 1;
61876 tmp = comp_ctx->curr_func.shuffle3;
61877 if (op_flags & DUK__EMIT_FLAG_C_IS_TARGET) {
61878 /* Output shuffle needed after main operation */
61879 c_out = c;
61880 } else {
61881 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, c));
61882 }
61883 c = tmp;
61884 } else {
61885 DUK_D(DUK_DPRINT("out of regs: 'c' (reg) needs shuffling but does not fit into BC, c: %ld", (long) c));
61886 goto error_outofregs;
61887 }
61888 }
61889
61890 /* Main operation */
61891
61892 DUK_ASSERT_DISABLE(a >= DUK_BC_A_MIN); /* unsigned */
61893 DUK_ASSERT(a <= DUK_BC_A_MAX);
61894 DUK_ASSERT_DISABLE(b >= DUK_BC_B_MIN); /* unsigned */
61895 DUK_ASSERT(b <= DUK_BC_B_MAX);
61896 DUK_ASSERT_DISABLE(c >= DUK_BC_C_MIN); /* unsigned */
61897 DUK_ASSERT(c <= DUK_BC_C_MAX);
61898
61899 ins |= DUK_ENC_OP_A_B_C(op_flags & 0xff, a, b, c);
61900 duk__emit(comp_ctx, ins);
61901
61902 /* NEXTENUM needs a jump slot right after the main instruction.
61903 * When the JUMP is taken, output spilling is not needed so this
61904 * workaround is possible. The jump slot PC is exceptionally
61905 * plumbed through comp_ctx to minimize call sites.
61906 */
61907 if (op_flags & DUK__EMIT_FLAG_RESERVE_JUMPSLOT) {
61908 comp_ctx->emit_jumpslot_pc = duk__get_current_pc(comp_ctx);
61909 duk__emit_abc(comp_ctx, DUK_OP_JUMP, 0);
61910 }
61911
61912 /* Output shuffling: only one output register is realistically possible.
61913 *
61914 * (Zero would normally be an OK marker value: if the target register
61915 * was zero, it would never be shuffled. But with DUK_USE_SHUFFLE_TORTURE
61916 * this is no longer true, so use -1 as a marker instead.)
61917 */
61918
61919 if (a_out >= 0) {
61920 DUK_ASSERT(b_out < 0);
61921 DUK_ASSERT(c_out < 0);
61922 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, a, a_out));
61923
61924 if (op == DUK_OP_CSVAR) {
61925 /* Special handling for CSVAR shuffling. The variable lookup
61926 * results in a <value, this binding> pair in successive
61927 * registers so use two shuffle registers and two output
61928 * loads. (In practice this is dead code because temp/const
61929 * limit is reached first.)
61930 */
61931 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, a + 1, a_out + 1));
61932 }
61933 } else if (b_out >= 0) {
61934 DUK_ASSERT(a_out < 0);
61935 DUK_ASSERT(c_out < 0);
61936 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, b, b_out));
61937 } else if (c_out >= 0) {
61938 DUK_ASSERT(b_out < 0);
61939 DUK_ASSERT(c_out < 0);
61940 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, c, c_out));
61941 }
61942
61943 return;
61944
61945 error_outofregs:
61946 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
61947}
61948
61949/* For many of the helpers below it'd be technically correct to add
61950 * "no shuffle" flags for parameters passed in as zero. For example,
61951 * duk__emit_a_b() should call duk__emit_a_b_c() with C set to 0, and
61952 * DUK__EMIT_FLAG_NO_SHUFFLE_C added to op_flags. However, since the
61953 * C value is 0, it'll never get shuffled so adding the flag is just
61954 * unnecessary additional code. This is unfortunately not true for
61955 * "shuffle torture" mode which needs special handling.
61956 */
61957
61958DUK_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) {
61959#if defined(DUK_USE_SHUFFLE_TORTURE)
61960 op_flags |= DUK__EMIT_FLAG_NO_SHUFFLE_C;
61961#endif
61962 duk__emit_a_b_c(comp_ctx, op_flags, a, b, 0);
61963}
61964
61965DUK_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) {
61966#if defined(DUK_USE_SHUFFLE_TORTURE)
61967 op_flags |= DUK__EMIT_FLAG_NO_SHUFFLE_A;
61968#endif
61969 duk__emit_a_b_c(comp_ctx, op_flags, 0, b, c);
61970}
61971
61972#if 0 /* unused */
61973DUK_LOCAL void duk__emit_a(duk_compiler_ctx *comp_ctx, int op_flags, int a) {
61974#if defined(DUK_USE_SHUFFLE_TORTURE)
61975 op_flags |= DUK__EMIT_FLAG_NO_SHUFFLE_B | DUK__EMIT_FLAG_NO_SHUFFLE_C;
61976#endif
61977 duk__emit_a_b_c(comp_ctx, op_flags, a, 0, 0);
61978}
61979#endif
61980
61981DUK_LOCAL void duk__emit_b(duk_compiler_ctx *comp_ctx, duk_small_uint_t op_flags, duk_regconst_t b) {
61982#if defined(DUK_USE_SHUFFLE_TORTURE)
61983 op_flags |= DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_NO_SHUFFLE_C;
61984#endif
61985 duk__emit_a_b_c(comp_ctx, op_flags, 0, b, 0);
61986}
61987
61988DUK_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) {
61989 duk_instr_t ins;
61990 duk_int_t tmp;
61991
61992 /* allow caller to give a const number with the DUK__CONST_MARKER */
61993 bc = bc & (~DUK__CONST_MARKER);
61994
61995 DUK_ASSERT_DISABLE((op_flags & 0xff) >= DUK_BC_OP_MIN); /* unsigned */
61996 DUK_ASSERT((op_flags & 0xff) <= DUK_BC_OP_MAX);
61997 DUK_ASSERT_DISABLE(bc >= DUK_BC_BC_MIN); /* unsigned */
61998 DUK_ASSERT(bc <= DUK_BC_BC_MAX);
61999 DUK_ASSERT((bc & DUK__CONST_MARKER) == 0);
62000
62001 if (bc <= DUK_BC_BC_MAX) {
62002 ;
62003 } else {
62004 /* No BC shuffling now. */
62005 goto error_outofregs;
62006 }
62007
62008#if defined(DUK_USE_SHUFFLE_TORTURE)
62009 if (a <= DUK_BC_A_MAX && (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A)) {
62010#else
62011 if (a <= DUK_BC_A_MAX) {
62012#endif
62013 ins = DUK_ENC_OP_A_BC(op_flags & 0xff, a, bc);
62014 duk__emit(comp_ctx, ins);
62015 } else if (op_flags & DUK__EMIT_FLAG_NO_SHUFFLE_A) {
62016 goto error_outofregs;
62017 } else if (a <= DUK_BC_BC_MAX) {
62018 comp_ctx->curr_func.needs_shuffle = 1;
62019 tmp = comp_ctx->curr_func.shuffle1;
62020 ins = DUK_ENC_OP_A_BC(op_flags & 0xff, tmp, bc);
62021 if (op_flags & DUK__EMIT_FLAG_A_IS_SOURCE) {
62022 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_LDREG, tmp, a));
62023 duk__emit(comp_ctx, ins);
62024 } else {
62025 duk__emit(comp_ctx, ins);
62026 duk__emit(comp_ctx, DUK_ENC_OP_A_BC(DUK_OP_STREG, tmp, a));
62027 }
62028 } else {
62029 goto error_outofregs;
62030 }
62031 return;
62032
62033 error_outofregs:
62034 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
62035}
62036
62037DUK_LOCAL void duk__emit_bc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t bc) {
62038#if defined(DUK_USE_SHUFFLE_TORTURE)
62039 op |= DUK__EMIT_FLAG_NO_SHUFFLE_A;
62040#endif
62041 duk__emit_a_bc(comp_ctx, op, 0, bc);
62042}
62043
62044DUK_LOCAL void duk__emit_abc(duk_compiler_ctx *comp_ctx, duk_small_uint_t op, duk_regconst_t abc) {
62045 duk_instr_t ins;
62046
62047 DUK_ASSERT_DISABLE(op >= DUK_BC_OP_MIN); /* unsigned */
62048 DUK_ASSERT(op <= DUK_BC_OP_MAX);
62049 DUK_ASSERT_DISABLE(abc >= DUK_BC_ABC_MIN); /* unsigned */
62050 DUK_ASSERT(abc <= DUK_BC_ABC_MAX);
62051 DUK_ASSERT((abc & DUK__CONST_MARKER) == 0);
62052
62053 if (abc <= DUK_BC_ABC_MAX) {
62054 ;
62055 } else {
62056 goto error_outofregs;
62057 }
62058 ins = DUK_ENC_OP_ABC(op, abc);
62059 DUK_DDD(DUK_DDDPRINT("duk__emit_abc: 0x%08lx line=%ld pc=%ld op=%ld (%!C) abc=%ld (%!I)",
62060 (unsigned long) ins, (long) comp_ctx->curr_token.start_line,
62061 (long) duk__get_current_pc(comp_ctx), (long) op, (long) op,
62062 (long) abc, (duk_instr_t) ins));
62063 duk__emit(comp_ctx, ins);
62064 return;
62065
62066 error_outofregs:
62067 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
62068}
62069
62070DUK_LOCAL void duk__emit_load_int32_raw(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val, duk_small_uint_t op_flags) {
62071 /* XXX: Shuffling support could be implemented here so that LDINT+LDINTX
62072 * would only shuffle once (instead of twice). The current code works
62073 * though, and has a smaller compiler footprint.
62074 */
62075
62076 if ((val >= (duk_int32_t) DUK_BC_BC_MIN - (duk_int32_t) DUK_BC_LDINT_BIAS) &&
62077 (val <= (duk_int32_t) DUK_BC_BC_MAX - (duk_int32_t) DUK_BC_LDINT_BIAS)) {
62078 DUK_DDD(DUK_DDDPRINT("emit LDINT to reg %ld for %ld", (long) reg, (long) val));
62079 duk__emit_a_bc(comp_ctx, DUK_OP_LDINT | op_flags, reg, (duk_regconst_t) (val + (duk_int32_t) DUK_BC_LDINT_BIAS));
62080 } else {
62081 duk_int32_t hi = val >> DUK_BC_LDINTX_SHIFT;
62082 duk_int32_t lo = val & ((((duk_int32_t) 1) << DUK_BC_LDINTX_SHIFT) - 1);
62083 DUK_ASSERT(lo >= 0);
62084 DUK_DDD(DUK_DDDPRINT("emit LDINT+LDINTX to reg %ld for %ld -> hi %ld, lo %ld",
62085 (long) reg, (long) val, (long) hi, (long) lo));
62086 duk__emit_a_bc(comp_ctx, DUK_OP_LDINT | op_flags, reg, (duk_regconst_t) (hi + (duk_int32_t) DUK_BC_LDINT_BIAS));
62087 duk__emit_a_bc(comp_ctx, DUK_OP_LDINTX | op_flags, reg, (duk_regconst_t) lo);
62088 }
62089}
62090
62091DUK_LOCAL void duk__emit_load_int32(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val) {
62092 duk__emit_load_int32_raw(comp_ctx, reg, val, 0 /*op_flags*/);
62093}
62094
62095#if defined(DUK_USE_SHUFFLE_TORTURE)
62096/* Used by duk__emit*() calls so that we don't shuffle the loadints that
62097 * are needed to handle indirect opcodes.
62098 */
62099DUK_LOCAL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val) {
62100 duk__emit_load_int32_raw(comp_ctx, reg, val, DUK__EMIT_FLAG_NO_SHUFFLE_A /*op_flags*/);
62101}
62102#else
62103DUK_LOCAL void duk__emit_load_int32_noshuffle(duk_compiler_ctx *comp_ctx, duk_reg_t reg, duk_int32_t val) {
62104 /* When torture not enabled, can just use the same helper because
62105 * 'reg' won't get spilled.
62106 */
62107 DUK_ASSERT(reg <= DUK_BC_A_MAX);
62108 duk__emit_load_int32(comp_ctx, reg, val);
62109}
62110#endif
62111
62112DUK_LOCAL void duk__emit_jump(duk_compiler_ctx *comp_ctx, duk_int_t target_pc) {
62113 duk_int_t curr_pc;
62114 duk_int_t offset;
62115
62116 curr_pc = (duk_int_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) / sizeof(duk_compiler_instr));
62117 offset = (duk_int_t) target_pc - (duk_int_t) curr_pc - 1;
62118 DUK_ASSERT(offset + DUK_BC_JUMP_BIAS >= DUK_BC_ABC_MIN);
62119 DUK_ASSERT(offset + DUK_BC_JUMP_BIAS <= DUK_BC_ABC_MAX);
62120 duk__emit_abc(comp_ctx, DUK_OP_JUMP, (duk_regconst_t) (offset + DUK_BC_JUMP_BIAS));
62121}
62122
62123DUK_LOCAL duk_int_t duk__emit_jump_empty(duk_compiler_ctx *comp_ctx) {
62124 duk_int_t ret;
62125
62126 ret = duk__get_current_pc(comp_ctx); /* useful for patching jumps later */
62127 duk__emit_op_only(comp_ctx, DUK_OP_JUMP);
62128 return ret;
62129}
62130
62131/* Insert an empty jump in the middle of code emitted earlier. This is
62132 * currently needed for compiling for-in.
62133 */
62134DUK_LOCAL void duk__insert_jump_entry(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc) {
62135#if defined(DUK_USE_PC2LINE)
62136 duk_int_t line;
62137#endif
62138 duk_compiler_instr *instr;
62139 duk_size_t offset;
62140
62141 offset = jump_pc * sizeof(duk_compiler_instr),
62142 instr = (duk_compiler_instr *) (void *)
62143 DUK_BW_INSERT_ENSURE_AREA(comp_ctx->thr,
62144 &comp_ctx->curr_func.bw_code,
62145 offset,
62146 sizeof(duk_compiler_instr));
62147
62148#if defined(DUK_USE_PC2LINE)
62149 line = comp_ctx->curr_token.start_line; /* approximation, close enough */
62150#endif
62151 instr->ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, 0);
62152#if defined(DUK_USE_PC2LINE)
62153 instr->line = line;
62154#endif
62155
62156 DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, sizeof(duk_compiler_instr));
62157 if (DUK_UNLIKELY(DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) > DUK_USE_ESBC_MAX_BYTES)) {
62158 goto fail_bc_limit;
62159 }
62160 return;
62161
62162 fail_bc_limit:
62163 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_BYTECODE_LIMIT);
62164}
62165
62166/* Does not assume that jump_pc contains a DUK_OP_JUMP previously; this is intentional
62167 * to allow e.g. an INVALID opcode be overwritten with a JUMP (label management uses this).
62168 */
62169DUK_LOCAL void duk__patch_jump(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc, duk_int_t target_pc) {
62170 duk_compiler_instr *instr;
62171 duk_int_t offset;
62172
62173 /* allow negative PCs, behave as a no-op */
62174 if (jump_pc < 0) {
62175 DUK_DDD(DUK_DDDPRINT("duk__patch_jump(): nop call, jump_pc=%ld (<0), target_pc=%ld",
62176 (long) jump_pc, (long) target_pc));
62177 return;
62178 }
62179 DUK_ASSERT(jump_pc >= 0);
62180
62181 /* XXX: range assert */
62182 instr = duk__get_instr_ptr(comp_ctx, jump_pc);
62183 DUK_ASSERT(instr != NULL);
62184
62185 /* XXX: range assert */
62186 offset = target_pc - jump_pc - 1;
62187
62188 instr->ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, offset + DUK_BC_JUMP_BIAS);
62189 DUK_DDD(DUK_DDDPRINT("duk__patch_jump(): jump_pc=%ld, target_pc=%ld, offset=%ld",
62190 (long) jump_pc, (long) target_pc, (long) offset));
62191}
62192
62193DUK_LOCAL void duk__patch_jump_here(duk_compiler_ctx *comp_ctx, duk_int_t jump_pc) {
62194 duk__patch_jump(comp_ctx, jump_pc, duk__get_current_pc(comp_ctx));
62195}
62196
62197DUK_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) {
62198 duk_compiler_instr *instr;
62199
62200 DUK_ASSERT((reg_catch & DUK__CONST_MARKER) == 0);
62201
62202 instr = duk__get_instr_ptr(comp_ctx, ldconst_pc);
62203 DUK_ASSERT(DUK_DEC_OP(instr->ins) == DUK_OP_LDCONST);
62204 DUK_ASSERT(instr != NULL);
62205 if (const_varname & DUK__CONST_MARKER) {
62206 /* Have a catch variable. */
62207 const_varname = const_varname & (~DUK__CONST_MARKER);
62208 if (reg_catch > DUK_BC_BC_MAX || const_varname > DUK_BC_BC_MAX) {
62209 /* Catch attempts to use out-of-range reg/const. Without this
62210 * check Duktape 0.12.0 could generate invalid code which caused
62211 * an assert failure on execution. This error is triggered e.g.
62212 * for functions with a lot of constants and a try-catch statement.
62213 * Shuffling or opcode semantics change is needed to fix the issue.
62214 * See: test-bug-trycatch-many-constants.js.
62215 */
62216 DUK_D(DUK_DPRINT("failed to patch trycatch: flags=%ld, reg_catch=%ld, const_varname=%ld (0x%08lx)",
62217 (long) flags, (long) reg_catch, (long) const_varname, (long) const_varname));
62218 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_REG_LIMIT);
62219 }
62220 instr->ins |= DUK_ENC_OP_A_BC(0, 0, const_varname);
62221 } else {
62222 /* No catch variable, e.g. a try-finally; replace LDCONST with
62223 * NOP to avoid a bogus LDCONST.
62224 */
62225 instr->ins = DUK_ENC_OP(DUK_OP_NOP);
62226 }
62227
62228 instr = duk__get_instr_ptr(comp_ctx, trycatch_pc);
62229 DUK_ASSERT(instr != NULL);
62230 DUK_ASSERT_DISABLE(flags >= DUK_BC_A_MIN);
62231 DUK_ASSERT(flags <= DUK_BC_A_MAX);
62232 instr->ins = DUK_ENC_OP_A_BC(DUK_OP_TRYCATCH, flags, reg_catch);
62233}
62234
62235DUK_LOCAL void duk__emit_if_false_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst) {
62236 duk_small_uint_t op;
62237
62238 op = DUK__ISREG(regconst) ? DUK_OP_IFFALSE_R : DUK_OP_IFFALSE_C;
62239 duk__emit_bc(comp_ctx, op, regconst); /* helper will remove const flag */
62240}
62241
62242DUK_LOCAL void duk__emit_if_true_skip(duk_compiler_ctx *comp_ctx, duk_regconst_t regconst) {
62243 duk_small_uint_t op;
62244
62245 op = DUK__ISREG(regconst) ? DUK_OP_IFTRUE_R : DUK_OP_IFTRUE_C;
62246 duk__emit_bc(comp_ctx, op, regconst); /* helper will remove const flag */
62247}
62248
62249DUK_LOCAL void duk__emit_invalid(duk_compiler_ctx *comp_ctx) {
62250 duk__emit_op_only(comp_ctx, DUK_OP_INVALID);
62251}
62252
62253/*
62254 * Peephole optimizer for finished bytecode.
62255 *
62256 * Does not remove opcodes; currently only straightens out unconditional
62257 * jump chains which are generated by several control structures.
62258 */
62259
62260DUK_LOCAL void duk__peephole_optimize_bytecode(duk_compiler_ctx *comp_ctx) {
62262 duk_small_uint_t iter;
62263 duk_int_t i, n;
62264 duk_int_t count_opt;
62265
62266 bc = (duk_compiler_instr *) (void *) DUK_BW_GET_BASEPTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code);
62267#if defined(DUK_USE_BUFLEN16)
62268 /* No need to assert, buffer size maximum is 0xffff. */
62269#else
62270 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 */
62271#endif
62272 n = (duk_int_t) (DUK_BW_GET_SIZE(comp_ctx->thr, &comp_ctx->curr_func.bw_code) / sizeof(duk_compiler_instr));
62273
62274 for (iter = 0; iter < DUK_COMPILER_PEEPHOLE_MAXITER; iter++) {
62275 count_opt = 0;
62276
62277 for (i = 0; i < n; i++) {
62278 duk_instr_t ins;
62279 duk_int_t target_pc1;
62280 duk_int_t target_pc2;
62281
62282 ins = bc[i].ins;
62283 if (DUK_DEC_OP(ins) != DUK_OP_JUMP) {
62284 continue;
62285 }
62286
62287 target_pc1 = i + 1 + DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS;
62288 DUK_DDD(DUK_DDDPRINT("consider jump at pc %ld; target_pc=%ld", (long) i, (long) target_pc1));
62289 DUK_ASSERT(target_pc1 >= 0);
62290 DUK_ASSERT(target_pc1 < n);
62291
62292 /* Note: if target_pc1 == i, we'll optimize a jump to itself.
62293 * This does not need to be checked for explicitly; the case
62294 * is rare and max iter breaks us out.
62295 */
62296
62297 ins = bc[target_pc1].ins;
62298 if (DUK_DEC_OP(ins) != DUK_OP_JUMP) {
62299 continue;
62300 }
62301
62302 target_pc2 = target_pc1 + 1 + DUK_DEC_ABC(ins) - DUK_BC_JUMP_BIAS;
62303
62304 DUK_DDD(DUK_DDDPRINT("optimizing jump at pc %ld; old target is %ld -> new target is %ld",
62305 (long) i, (long) target_pc1, (long) target_pc2));
62306
62307 bc[i].ins = DUK_ENC_OP_ABC(DUK_OP_JUMP, target_pc2 - (i + 1) + DUK_BC_JUMP_BIAS);
62308
62309 count_opt++;
62310 }
62311
62312 DUK_DD(DUK_DDPRINT("optimized %ld jumps on peephole round %ld", (long) count_opt, (long) (iter + 1)));
62313
62314 if (count_opt == 0) {
62315 break;
62316 }
62317 }
62318}
62319
62320/*
62321 * Intermediate value helpers
62322 */
62323
62324/* Flags for intermediate value coercions. A flag for using a forced reg
62325 * is not needed, the forced_reg argument suffices and generates better
62326 * code (it is checked as it is used).
62327 */
62328#define DUK__IVAL_FLAG_ALLOW_CONST (1 << 0) /* allow a constant to be returned */
62329#define DUK__IVAL_FLAG_REQUIRE_TEMP (1 << 1) /* require a (mutable) temporary as a result (or a const if allowed) */
62330#define DUK__IVAL_FLAG_REQUIRE_SHORT (1 << 2) /* require a short (8-bit) reg/const which fits into bytecode B/C slot */
62331
62332/* XXX: some code might benefit from DUK__SETTEMP_IFTEMP(ctx,x) */
62333
62334#if 0 /* enable manually for dumping */
62335#define DUK__DUMP_ISPEC(compctx,ispec) do { duk__dump_ispec((compctx), (ispec)); } while (0)
62336#define DUK__DUMP_IVALUE(compctx,ivalue) do { duk__dump_ivalue((compctx), (ivalue)); } while (0)
62337
62338DUK_LOCAL void duk__dump_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *x) {
62339 DUK_D(DUK_DPRINT("ispec dump: t=%ld regconst=0x%08lx, valstack_idx=%ld, value=%!T",
62340 (long) x->t, (unsigned long) x->regconst, (long) x->valstack_idx,
62341 duk_get_tval((duk_context *) comp_ctx->thr, x->valstack_idx)));
62342}
62343DUK_LOCAL void duk__dump_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
62344 DUK_D(DUK_DPRINT("ivalue dump: t=%ld op=%ld "
62345 "x1={t=%ld regconst=0x%08lx valstack_idx=%ld value=%!T} "
62346 "x2={t=%ld regconst=0x%08lx valstack_idx=%ld value=%!T}",
62347 (long) x->t, (long) x->op,
62348 (long) x->x1.t, (unsigned long) x->x1.regconst, (long) x->x1.valstack_idx,
62349 duk_get_tval((duk_context *) comp_ctx->thr, x->x1.valstack_idx),
62350 (long) x->x2.t, (unsigned long) x->x2.regconst, (long) x->x2.valstack_idx,
62351 duk_get_tval((duk_context *) comp_ctx->thr, x->x2.valstack_idx)));
62352}
62353#else
62354#define DUK__DUMP_ISPEC(comp_ctx,x) do {} while (0)
62355#define DUK__DUMP_IVALUE(comp_ctx,x) do {} while (0)
62356#endif
62357
62358DUK_LOCAL void duk__ivalue_regconst(duk_ivalue *x, duk_regconst_t regconst) {
62359 x->t = DUK_IVAL_PLAIN;
62360 x->x1.t = DUK_ISPEC_REGCONST;
62361 x->x1.regconst = (duk_regconst_t) regconst;
62362}
62363
62364DUK_LOCAL void duk__ivalue_plain_fromstack(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
62365 x->t = DUK_IVAL_PLAIN;
62366 x->x1.t = DUK_ISPEC_VALUE;
62367 duk_replace((duk_context *) comp_ctx->thr, x->x1.valstack_idx);
62368}
62369
62370DUK_LOCAL void duk__ivalue_var_fromstack(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
62371 x->t = DUK_IVAL_VAR;
62372 x->x1.t = DUK_ISPEC_VALUE;
62373 duk_replace((duk_context *) comp_ctx->thr, x->x1.valstack_idx);
62374}
62375
62376DUK_LOCAL_DECL void duk__ivalue_var_hstring(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_hstring *h) {
62377 DUK_ASSERT(h != NULL);
62378 duk_push_hstring((duk_context *) comp_ctx->thr, h);
62379 duk__ivalue_var_fromstack(comp_ctx, x);
62380}
62381
62382DUK_LOCAL void duk__copy_ispec(duk_compiler_ctx *comp_ctx, duk_ispec *src, duk_ispec *dst) {
62383 duk_context *ctx = (duk_context *) comp_ctx->thr;
62384
62385 dst->t = src->t;
62386 dst->regconst = src->regconst;
62387 duk_copy(ctx, src->valstack_idx, dst->valstack_idx);
62388}
62389
62390DUK_LOCAL void duk__copy_ivalue(duk_compiler_ctx *comp_ctx, duk_ivalue *src, duk_ivalue *dst) {
62391 duk_context *ctx = (duk_context *) comp_ctx->thr;
62392
62393 dst->t = src->t;
62394 dst->op = src->op;
62395 dst->x1.t = src->x1.t;
62396 dst->x1.regconst = src->x1.regconst;
62397 dst->x2.t = src->x2.t;
62398 dst->x2.regconst = src->x2.regconst;
62399 duk_copy(ctx, src->x1.valstack_idx, dst->x1.valstack_idx);
62400 duk_copy(ctx, src->x2.valstack_idx, dst->x2.valstack_idx);
62401}
62402
62403DUK_LOCAL duk_reg_t duk__alloctemps(duk_compiler_ctx *comp_ctx, duk_small_int_t num) {
62404 duk_reg_t res;
62405
62406 res = comp_ctx->curr_func.temp_next;
62407 comp_ctx->curr_func.temp_next += num;
62408
62409 if (comp_ctx->curr_func.temp_next > DUK__MAX_TEMPS) { /* == DUK__MAX_TEMPS is OK */
62410 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_TEMP_LIMIT);
62411 }
62412
62413 /* maintain highest 'used' temporary, needed to figure out nregs of function */
62414 if (comp_ctx->curr_func.temp_next > comp_ctx->curr_func.temp_max) {
62415 comp_ctx->curr_func.temp_max = comp_ctx->curr_func.temp_next;
62416 }
62417
62418 return res;
62419}
62420
62421DUK_LOCAL duk_reg_t duk__alloctemp(duk_compiler_ctx *comp_ctx) {
62422 return duk__alloctemps(comp_ctx, 1);
62423}
62424
62425DUK_LOCAL void duk__settemp_checkmax(duk_compiler_ctx *comp_ctx, duk_reg_t temp_next) {
62426 comp_ctx->curr_func.temp_next = temp_next;
62427 if (temp_next > comp_ctx->curr_func.temp_max) {
62428 comp_ctx->curr_func.temp_max = temp_next;
62429 }
62430}
62431
62432/* get const for value at valstack top */
62433DUK_LOCAL duk_regconst_t duk__getconst(duk_compiler_ctx *comp_ctx) {
62434 duk_hthread *thr = comp_ctx->thr;
62435 duk_context *ctx = (duk_context *) thr;
62436 duk_compiler_func *f = &comp_ctx->curr_func;
62437 duk_tval *tv1;
62438 duk_int_t i, n, n_check;
62439
62440 n = (duk_int_t) duk_get_length(ctx, f->consts_idx);
62441
62442 tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1);
62443 DUK_ASSERT(tv1 != NULL);
62444
62445#if defined(DUK_USE_FASTINT)
62446 /* Explicit check for fastint downgrade. */
62447 DUK_TVAL_CHKFAST_INPLACE_SLOW(tv1);
62448#endif
62449
62450 /* Sanity workaround for handling functions with a large number of
62451 * constants at least somewhat reasonably. Otherwise checking whether
62452 * we already have the constant would grow very slow (as it is O(N^2)).
62453 */
62454 n_check = (n > DUK__GETCONST_MAX_CONSTS_CHECK ? DUK__GETCONST_MAX_CONSTS_CHECK : n);
62455 for (i = 0; i < n_check; i++) {
62456 duk_tval *tv2 = DUK_HOBJECT_A_GET_VALUE_PTR(thr->heap, f->h_consts, i);
62457
62458 /* Strict equality is NOT enough, because we cannot use the same
62459 * constant for e.g. +0 and -0.
62460 */
62461 if (duk_js_samevalue(tv1, tv2)) {
62462 DUK_DDD(DUK_DDDPRINT("reused existing constant for %!T -> const index %ld",
62463 (duk_tval *) tv1, (long) i));
62464 duk_pop(ctx);
62465 return (duk_regconst_t) (i | DUK__CONST_MARKER);
62466 }
62467 }
62468
62469 if (n > DUK__MAX_CONSTS) {
62470 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_CONST_LIMIT);
62471 }
62472
62473 DUK_DDD(DUK_DDDPRINT("allocating new constant for %!T -> const index %ld",
62474 (duk_tval *) tv1, (long) n));
62475 (void) duk_put_prop_index(ctx, f->consts_idx, n); /* invalidates tv1, tv2 */
62476 return (duk_regconst_t) (n | DUK__CONST_MARKER);
62477}
62478
62479DUK_LOCAL duk_bool_t duk__const_needs_refcount(duk_compiler_ctx *comp_ctx, duk_regconst_t rc) {
62480#if defined(DUK_USE_REFERENCE_COUNTING)
62481 duk_context *ctx = (duk_context *) comp_ctx->thr;
62482 duk_compiler_func *f = &comp_ctx->curr_func;
62483 duk_bool_t ret;
62484
62485 DUK_ASSERT((rc & DUK__CONST_MARKER) == 0); /* caller removes const marker */
62486 (void) duk_get_prop_index(ctx, f->consts_idx, (duk_uarridx_t) rc);
62487 ret = !duk_is_number(ctx, -1); /* now only number/string, so conservative check */
62488 duk_pop(ctx);
62489 return ret;
62490#else
62491 DUK_ASSERT((rc & DUK__CONST_MARKER) == 0); /* caller removes const marker */
62492 return 0;
62493#endif
62494}
62495
62496/* Get the value represented by an duk_ispec to a register or constant.
62497 * The caller can control the result by indicating whether or not:
62498 *
62499 * (1) a constant is allowed (sometimes the caller needs the result to
62500 * be in a register)
62501 *
62502 * (2) a temporary register is required (usually when caller requires
62503 * the register to be safely mutable; normally either a bound
62504 * register or a temporary register are both OK)
62505 *
62506 * (3) a forced register target needs to be used
62507 *
62508 * Bytecode may be emitted to generate the necessary value. The return
62509 * value is either a register or a constant.
62510 */
62511
62512DUK_LOCAL
62513duk_regconst_t duk__ispec_toregconst_raw(duk_compiler_ctx *comp_ctx,
62514 duk_ispec *x,
62515 duk_reg_t forced_reg,
62516 duk_small_uint_t flags) {
62517 duk_hthread *thr = comp_ctx->thr;
62518 duk_context *ctx = (duk_context *) thr;
62519
62520 DUK_DDD(DUK_DDDPRINT("duk__ispec_toregconst_raw(): x={%ld:%ld:%!T}, "
62521 "forced_reg=%ld, flags 0x%08lx: allow_const=%ld require_temp=%ld require_short=%ld",
62522 (long) x->t,
62523 (long) x->regconst,
62524 (duk_tval *) duk_get_tval(ctx, x->valstack_idx),
62525 (long) forced_reg,
62526 (unsigned long) flags,
62527 (long) ((flags & DUK__IVAL_FLAG_ALLOW_CONST) ? 1 : 0),
62528 (long) ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) ? 1 : 0),
62529 (long) ((flags & DUK__IVAL_FLAG_REQUIRE_SHORT) ? 1 : 0)));
62530
62531 switch (x->t) {
62532 case DUK_ISPEC_VALUE: {
62533 duk_tval *tv;
62534
62535 tv = DUK_GET_TVAL_POSIDX(ctx, x->valstack_idx);
62536 DUK_ASSERT(tv != NULL);
62537
62538 switch (DUK_TVAL_GET_TAG(tv)) {
62539 case DUK_TAG_UNDEFINED: {
62540 /* Note: although there is no 'undefined' literal, undefined
62541 * values can occur during compilation as a result of e.g.
62542 * the 'void' operator.
62543 */
62544 duk_reg_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
62545 duk__emit_bc(comp_ctx, DUK_OP_LDUNDEF, (duk_regconst_t) dest);
62546 return (duk_regconst_t) dest;
62547 }
62548 case DUK_TAG_NULL: {
62549 duk_reg_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
62550 duk__emit_bc(comp_ctx, DUK_OP_LDNULL, (duk_regconst_t) dest);
62551 return (duk_regconst_t) dest;
62552 }
62553 case DUK_TAG_BOOLEAN: {
62554 duk_reg_t dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
62555 duk__emit_bc(comp_ctx,
62556 (DUK_TVAL_GET_BOOLEAN(tv) ? DUK_OP_LDTRUE : DUK_OP_LDFALSE),
62557 (duk_regconst_t) dest);
62558 return (duk_regconst_t) dest;
62559 }
62560 case DUK_TAG_POINTER: {
62561 DUK_UNREACHABLE();
62562 break;
62563 }
62564 case DUK_TAG_STRING: {
62565 duk_hstring *h;
62566 duk_reg_t dest;
62567 duk_regconst_t constidx;
62568
62569 h = DUK_TVAL_GET_STRING(tv);
62570 DUK_UNREF(h);
62571 DUK_ASSERT(h != NULL);
62572
62573#if 0 /* XXX: to be implemented? */
62574 /* Use special opcodes to load short strings */
62575 if (DUK_HSTRING_GET_BYTELEN(h) <= 2) {
62576 /* Encode into a single opcode (18 bits can encode 1-2 bytes + length indicator) */
62577 } else if (DUK_HSTRING_GET_BYTELEN(h) <= 6) {
62578 /* Encode into a double constant (53 bits can encode 6*8 = 48 bits + 3-bit length */
62579 }
62580#endif
62581 duk_dup(ctx, x->valstack_idx);
62582 constidx = duk__getconst(comp_ctx);
62583
62584 if (flags & DUK__IVAL_FLAG_ALLOW_CONST) {
62585 return constidx;
62586 }
62587
62588 dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
62589 duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, (duk_regconst_t) dest, constidx);
62590 return (duk_regconst_t) dest;
62591 }
62592 case DUK_TAG_OBJECT: {
62593 DUK_UNREACHABLE();
62594 break;
62595 }
62596 case DUK_TAG_BUFFER: {
62597 DUK_UNREACHABLE();
62598 break;
62599 }
62600 case DUK_TAG_LIGHTFUNC: {
62601 DUK_UNREACHABLE();
62602 break;
62603 }
62604#if defined(DUK_USE_FASTINT)
62605 case DUK_TAG_FASTINT:
62606#endif
62607 default: {
62608 /* number */
62609 duk_reg_t dest;
62610 duk_regconst_t constidx;
62611 duk_double_t dval;
62612 duk_int32_t ival;
62613
62614 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
62615 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
62616 dval = DUK_TVAL_GET_NUMBER(tv);
62617
62618 if (!(flags & DUK__IVAL_FLAG_ALLOW_CONST)) {
62619 /* A number can be loaded either through a constant, using
62620 * LDINT, or using LDINT+LDINTX. LDINT is always a size win,
62621 * LDINT+LDINTX is not if the constant is used multiple times.
62622 * Currently always prefer LDINT+LDINTX over a double constant.
62623 */
62624
62625 if (duk_is_whole_get_int32_nonegzero(dval, &ival)) {
62626 dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
62627 duk__emit_load_int32(comp_ctx, dest, ival);
62628 return (duk_regconst_t) dest;
62629 }
62630 }
62631
62632 duk_dup(ctx, x->valstack_idx);
62633 constidx = duk__getconst(comp_ctx);
62634
62635 if (flags & DUK__IVAL_FLAG_ALLOW_CONST) {
62636 return constidx;
62637 } else {
62638 dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
62639 duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, (duk_regconst_t) dest, constidx);
62640 return (duk_regconst_t) dest;
62641 }
62642 }
62643 } /* end switch */
62644 }
62645 case DUK_ISPEC_REGCONST: {
62646 if (forced_reg >= 0) {
62647 if (x->regconst & DUK__CONST_MARKER) {
62648 duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, forced_reg, x->regconst);
62649 } else if (x->regconst != (duk_regconst_t) forced_reg) {
62650 duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, forced_reg, x->regconst);
62651 } else {
62652 ; /* already in correct reg */
62653 }
62654 return (duk_regconst_t) forced_reg;
62655 }
62656
62657 DUK_ASSERT(forced_reg < 0);
62658 if (x->regconst & DUK__CONST_MARKER) {
62659 if (!(flags & DUK__IVAL_FLAG_ALLOW_CONST)) {
62660 duk_reg_t dest = DUK__ALLOCTEMP(comp_ctx);
62661 duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, (duk_regconst_t) dest, x->regconst);
62662 return (duk_regconst_t) dest;
62663 }
62664 return x->regconst;
62665 }
62666
62667 DUK_ASSERT(forced_reg < 0 && !(x->regconst & DUK__CONST_MARKER));
62668 if ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) && !DUK__ISTEMP(comp_ctx, x->regconst)) {
62669 duk_reg_t dest = DUK__ALLOCTEMP(comp_ctx);
62670 duk__emit_a_bc(comp_ctx, DUK_OP_LDREG, (duk_regconst_t) dest, x->regconst);
62671 return (duk_regconst_t) dest;
62672 }
62673 return x->regconst;
62674 }
62675 default: {
62676 break;
62677 }
62678 }
62679
62680 DUK_ERROR_INTERNAL(thr);
62681 return 0;
62682}
62683
62684DUK_LOCAL void duk__ispec_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ispec *x, duk_reg_t forced_reg) {
62685 DUK_ASSERT(forced_reg >= 0);
62686 (void) duk__ispec_toregconst_raw(comp_ctx, x, forced_reg, 0 /*flags*/);
62687}
62688
62689/* Coerce an duk_ivalue to a 'plain' value by generating the necessary
62690 * arithmetic operations, property access, or variable access bytecode.
62691 * The duk_ivalue argument ('x') is converted into a plain value as a
62692 * side effect.
62693 */
62694DUK_LOCAL void duk__ivalue_toplain_raw(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_reg_t forced_reg) {
62695 duk_hthread *thr = comp_ctx->thr;
62696 duk_context *ctx = (duk_context *) thr;
62697
62698 DUK_DDD(DUK_DDDPRINT("duk__ivalue_toplain_raw(): x={t=%ld,op=%ld,x1={%ld:%ld:%!T},x2={%ld:%ld:%!T}}, "
62699 "forced_reg=%ld",
62700 (long) x->t, (long) x->op,
62701 (long) x->x1.t, (long) x->x1.regconst,
62702 (duk_tval *) duk_get_tval(ctx, x->x1.valstack_idx),
62703 (long) x->x2.t, (long) x->x2.regconst,
62704 (duk_tval *) duk_get_tval(ctx, x->x2.valstack_idx),
62705 (long) forced_reg));
62706
62707 switch (x->t) {
62708 case DUK_IVAL_PLAIN: {
62709 return;
62710 }
62711 /* XXX: support unary arithmetic ivalues (useful?) */
62712 case DUK_IVAL_ARITH: {
62713 duk_regconst_t arg1;
62714 duk_regconst_t arg2;
62715 duk_reg_t dest;
62716 duk_tval *tv1;
62717 duk_tval *tv2;
62718
62719 DUK_DDD(DUK_DDDPRINT("arith to plain conversion"));
62720
62721 /* inline arithmetic check for constant values */
62722 /* XXX: use the exactly same arithmetic function here as in executor */
62723 if (x->x1.t == DUK_ISPEC_VALUE && x->x2.t == DUK_ISPEC_VALUE && x->t == DUK_IVAL_ARITH) {
62724 tv1 = DUK_GET_TVAL_POSIDX(ctx, x->x1.valstack_idx);
62725 tv2 = DUK_GET_TVAL_POSIDX(ctx, x->x2.valstack_idx);
62726 DUK_ASSERT(tv1 != NULL);
62727 DUK_ASSERT(tv2 != NULL);
62728
62729 DUK_DDD(DUK_DDDPRINT("arith: tv1=%!T, tv2=%!T",
62730 (duk_tval *) tv1,
62731 (duk_tval *) tv2));
62732
62733 if (DUK_TVAL_IS_NUMBER(tv1) && DUK_TVAL_IS_NUMBER(tv2)) {
62734 duk_double_t d1 = DUK_TVAL_GET_NUMBER(tv1);
62735 duk_double_t d2 = DUK_TVAL_GET_NUMBER(tv2);
62736 duk_double_t d3;
62737 duk_bool_t accept_fold = 1;
62738
62739 DUK_DDD(DUK_DDDPRINT("arith inline check: d1=%lf, d2=%lf, op=%ld",
62740 (double) d1, (double) d2, (long) x->op));
62741 switch (x->op) {
62742 case DUK_OP_ADD: d3 = d1 + d2; break;
62743 case DUK_OP_SUB: d3 = d1 - d2; break;
62744 case DUK_OP_MUL: d3 = d1 * d2; break;
62745 case DUK_OP_DIV: d3 = d1 / d2; break;
62746 case DUK_OP_EXP: {
62747 d3 = (duk_double_t) duk_js_arith_pow((double) d1, (double) d2);
62748 break;
62749 }
62750 default: accept_fold = 0; break;
62751 }
62752
62753 if (accept_fold) {
62755 du.d = d3;
62756 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
62757 d3 = du.d;
62758
62759 x->t = DUK_IVAL_PLAIN;
62760 DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE);
62761 DUK_TVAL_SET_NUMBER(tv1, d3); /* old value is number: no refcount */
62762 return;
62763 }
62764 } else if (x->op == DUK_OP_ADD && DUK_TVAL_IS_STRING(tv1) && DUK_TVAL_IS_STRING(tv2)) {
62765 /* Inline string concatenation. No need to check for
62766 * symbols, as all inputs are valid Ecmascript strings.
62767 */
62768 duk_dup(ctx, x->x1.valstack_idx);
62769 duk_dup(ctx, x->x2.valstack_idx);
62770 duk_concat(ctx, 2);
62771 duk_replace(ctx, x->x1.valstack_idx);
62772 x->t = DUK_IVAL_PLAIN;
62773 DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE);
62774 return;
62775 }
62776 }
62777
62778 arg1 = duk__ispec_toregconst_raw(comp_ctx, &x->x1, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
62779 arg2 = duk__ispec_toregconst_raw(comp_ctx, &x->x2, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
62780
62781 /* If forced reg, use it as destination. Otherwise try to
62782 * use either coerced ispec if it is a temporary.
62783 */
62784 if (forced_reg >= 0) {
62785 dest = forced_reg;
62786 } else if (DUK__ISTEMP(comp_ctx, arg1)) {
62787 dest = (duk_reg_t) arg1;
62788 } else if (DUK__ISTEMP(comp_ctx, arg2)) {
62789 dest = (duk_reg_t) arg2;
62790 } else {
62791 dest = DUK__ALLOCTEMP(comp_ctx);
62792 }
62793
62794 DUK_ASSERT(DUK__ISREG(dest));
62795 duk__emit_a_b_c(comp_ctx, x->op | DUK__EMIT_FLAG_BC_REGCONST, (duk_regconst_t) dest, arg1, arg2);
62796
62797 duk__ivalue_regconst(x, (duk_regconst_t) dest);
62798 return;
62799 }
62800 case DUK_IVAL_PROP: {
62801 /* XXX: very similar to DUK_IVAL_ARITH - merge? */
62802 duk_regconst_t arg1;
62803 duk_regconst_t arg2;
62804 duk_reg_t dest;
62805
62806 /* Need a short reg/const, does not have to be a mutable temp. */
62807 arg1 = duk__ispec_toregconst_raw(comp_ctx, &x->x1, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
62808 arg2 = duk__ispec_toregconst_raw(comp_ctx, &x->x2, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_SHORT /*flags*/);
62809
62810 /* Pick a destination register. If either base value or key
62811 * happens to be a temp value, reuse it as the destination.
62812 *
62813 * XXX: The temp must be a "mutable" one, i.e. such that no
62814 * other expression is using it anymore. Here this should be
62815 * the case because the value of a property access expression
62816 * is neither the base nor the key, but the lookup result.
62817 */
62818
62819 if (forced_reg >= 0) {
62820 dest = forced_reg;
62821 } else if (DUK__ISTEMP(comp_ctx, arg1)) {
62822 dest = (duk_reg_t) arg1;
62823 } else if (DUK__ISTEMP(comp_ctx, arg2)) {
62824 dest = (duk_reg_t) arg2;
62825 } else {
62826 dest = DUK__ALLOCTEMP(comp_ctx);
62827 }
62828
62829 duk__emit_a_b_c(comp_ctx,
62830 DUK_OP_GETPROP | DUK__EMIT_FLAG_BC_REGCONST,
62831 (duk_regconst_t) dest,
62832 arg1,
62833 arg2);
62834
62835 duk__ivalue_regconst(x, (duk_regconst_t) dest);
62836 return;
62837 }
62838 case DUK_IVAL_VAR: {
62839 /* x1 must be a string */
62840 duk_reg_t dest;
62841 duk_reg_t reg_varbind;
62842 duk_regconst_t rc_varname;
62843
62844 DUK_ASSERT(x->x1.t == DUK_ISPEC_VALUE);
62845
62846 duk_dup(ctx, x->x1.valstack_idx);
62847 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
62848 duk__ivalue_regconst(x, (duk_regconst_t) reg_varbind);
62849 } else {
62850 dest = (forced_reg >= 0 ? forced_reg : DUK__ALLOCTEMP(comp_ctx));
62851 duk__emit_a_bc(comp_ctx, DUK_OP_GETVAR, (duk_regconst_t) dest, rc_varname);
62852 duk__ivalue_regconst(x, (duk_regconst_t) dest);
62853 }
62854 return;
62855 }
62856 case DUK_IVAL_NONE:
62857 default: {
62858 DUK_D(DUK_DPRINT("invalid ivalue type: %ld", (long) x->t));
62859 break;
62860 }
62861 }
62862
62863 DUK_ERROR_INTERNAL(thr);
62864 return;
62865}
62866
62867/* evaluate to plain value, no forced register (temp/bound reg both ok) */
62868DUK_LOCAL void duk__ivalue_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
62869 duk__ivalue_toplain_raw(comp_ctx, x, -1 /*forced_reg*/);
62870}
62871
62872/* evaluate to final form (e.g. coerce GETPROP to code), throw away temp */
62873DUK_LOCAL void duk__ivalue_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
62874 duk_reg_t temp;
62875
62876 /* If duk__ivalue_toplain_raw() allocates a temp, forget it and
62877 * restore next temp state.
62878 */
62879 temp = DUK__GETTEMP(comp_ctx);
62880 duk__ivalue_toplain_raw(comp_ctx, x, -1 /*forced_reg*/);
62881 DUK__SETTEMP(comp_ctx, temp);
62882}
62883
62884/* Coerce an duk_ivalue to a register or constant; result register may
62885 * be a temp or a bound register.
62886 *
62887 * The duk_ivalue argument ('x') is converted into a regconst as a
62888 * side effect.
62889 */
62890DUK_LOCAL
62891duk_regconst_t duk__ivalue_toregconst_raw(duk_compiler_ctx *comp_ctx,
62892 duk_ivalue *x,
62893 duk_reg_t forced_reg,
62894 duk_small_uint_t flags) {
62895 duk_hthread *thr = comp_ctx->thr;
62896 duk_context *ctx = (duk_context *) thr;
62897 duk_regconst_t reg;
62898 DUK_UNREF(thr);
62899 DUK_UNREF(ctx);
62900
62901 DUK_DDD(DUK_DDDPRINT("duk__ivalue_toregconst_raw(): x={t=%ld,op=%ld,x1={%ld:%ld:%!T},x2={%ld:%ld:%!T}}, "
62902 "forced_reg=%ld, flags 0x%08lx: allow_const=%ld require_temp=%ld require_short=%ld",
62903 (long) x->t, (long) x->op,
62904 (long) x->x1.t, (long) x->x1.regconst,
62905 (duk_tval *) duk_get_tval(ctx, x->x1.valstack_idx),
62906 (long) x->x2.t, (long) x->x2.regconst,
62907 (duk_tval *) duk_get_tval(ctx, x->x2.valstack_idx),
62908 (long) forced_reg,
62909 (unsigned long) flags,
62910 (long) ((flags & DUK__IVAL_FLAG_ALLOW_CONST) ? 1 : 0),
62911 (long) ((flags & DUK__IVAL_FLAG_REQUIRE_TEMP) ? 1 : 0),
62912 (long) ((flags & DUK__IVAL_FLAG_REQUIRE_SHORT) ? 1 : 0)));
62913
62914 /* first coerce to a plain value */
62915 duk__ivalue_toplain_raw(comp_ctx, x, forced_reg);
62916 DUK_ASSERT(x->t == DUK_IVAL_PLAIN);
62917
62918 /* then to a register */
62919 reg = duk__ispec_toregconst_raw(comp_ctx, &x->x1, forced_reg, flags);
62920 duk__ivalue_regconst(x, (duk_regconst_t) reg);
62921
62922 return reg;
62923}
62924
62925DUK_LOCAL duk_reg_t duk__ivalue_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
62926 return duk__ivalue_toregconst_raw(comp_ctx, x, -1, 0 /*flags*/);
62927}
62928
62929#if 0 /* unused */
62930DUK_LOCAL duk_reg_t duk__ivalue_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
62931 return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
62932}
62933#endif
62934
62935DUK_LOCAL void duk__ivalue_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *x, duk_int_t forced_reg) {
62936 DUK_ASSERT(forced_reg >= 0);
62937 (void) duk__ivalue_toregconst_raw(comp_ctx, x, forced_reg, 0 /*flags*/);
62938}
62939
62940DUK_LOCAL duk_regconst_t duk__ivalue_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
62941 return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
62942}
62943
62944DUK_LOCAL duk_regconst_t duk__ivalue_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *x) {
62945 return duk__ivalue_toregconst_raw(comp_ctx, x, -1, DUK__IVAL_FLAG_ALLOW_CONST | DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
62946}
62947
62948/* The issues below can be solved with better flags */
62949
62950/* XXX: many operations actually want toforcedtemp() -- brand new temp? */
62951/* XXX: need a toplain_ignore() which will only coerce a value to a temp
62952 * register if it might have a side effect. Side-effect free values do not
62953 * need to be coerced.
62954 */
62955
62956/*
62957 * Identifier handling
62958 */
62959
62960DUK_LOCAL duk_reg_t duk__lookup_active_register_binding(duk_compiler_ctx *comp_ctx) {
62961 duk_hthread *thr = comp_ctx->thr;
62962 duk_context *ctx = (duk_context *) thr;
62963 duk_hstring *h_varname;
62964 duk_reg_t ret;
62965
62966 DUK_DDD(DUK_DDDPRINT("resolving identifier reference to '%!T'",
62967 (duk_tval *) duk_get_tval(ctx, -1)));
62968
62969 /*
62970 * Special name handling
62971 */
62972
62973 h_varname = duk_known_hstring(ctx, -1);
62974
62975 if (h_varname == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)) {
62976 DUK_DDD(DUK_DDDPRINT("flagging function as accessing 'arguments'"));
62977 comp_ctx->curr_func.id_access_arguments = 1;
62978 }
62979
62980 /*
62981 * Inside one or more 'with' statements fall back to slow path always.
62982 * (See e.g. test-stmt-with.js.)
62983 */
62984
62985 if (comp_ctx->curr_func.with_depth > 0) {
62986 DUK_DDD(DUK_DDDPRINT("identifier lookup inside a 'with' -> fall back to slow path"));
62987 goto slow_path_own;
62988 }
62989
62990 /*
62991 * Any catch bindings ("catch (e)") also affect identifier binding.
62992 *
62993 * Currently, the varmap is modified for the duration of the catch
62994 * clause to ensure any identifier accesses with the catch variable
62995 * name will use slow path.
62996 */
62997
62998 duk_get_prop(ctx, comp_ctx->curr_func.varmap_idx);
62999 if (duk_is_number(ctx, -1)) {
63000 ret = duk_to_int(ctx, -1);
63001 duk_pop(ctx);
63002 } else {
63003 duk_pop(ctx);
63004 if (comp_ctx->curr_func.catch_depth > 0 || comp_ctx->curr_func.with_depth > 0) {
63005 DUK_DDD(DUK_DDDPRINT("slow path access from inside a try-catch or with needs _Varmap"));
63006 goto slow_path_own;
63007 } else {
63008 /* In this case we're doing a variable lookup that doesn't
63009 * match our own variables, so _Varmap won't be needed at
63010 * run time.
63011 */
63012 DUK_DDD(DUK_DDDPRINT("slow path access outside of try-catch and with, no need for _Varmap"));
63013 goto slow_path_notown;
63014 }
63015 }
63016
63017 DUK_DDD(DUK_DDDPRINT("identifier lookup -> reg %ld", (long) ret));
63018 return ret;
63019
63020 slow_path_notown:
63021 DUK_DDD(DUK_DDDPRINT("identifier lookup -> slow path, not own variable"));
63022
63023 comp_ctx->curr_func.id_access_slow = 1;
63024 return (duk_reg_t) -1;
63025
63026 slow_path_own:
63027 DUK_DDD(DUK_DDDPRINT("identifier lookup -> slow path, may be own variable"));
63028
63029 comp_ctx->curr_func.id_access_slow = 1;
63030 comp_ctx->curr_func.id_access_slow_own = 1;
63031 return (duk_reg_t) -1;
63032}
63033
63034/* Lookup an identifier name in the current varmap, indicating whether the
63035 * identifier is register-bound and if not, allocating a constant for the
63036 * identifier name. Returns 1 if register-bound, 0 otherwise. Caller can
63037 * also check (out_reg_varbind >= 0) to check whether or not identifier is
63038 * register bound. The caller must NOT use out_rc_varname at all unless
63039 * return code is 0 or out_reg_varbind is < 0; this is becuase out_rc_varname
63040 * is unsigned and doesn't have a "unused" / none value.
63041 */
63042DUK_LOCAL duk_bool_t duk__lookup_lhs(duk_compiler_ctx *comp_ctx, duk_reg_t *out_reg_varbind, duk_regconst_t *out_rc_varname) {
63043 duk_hthread *thr = comp_ctx->thr;
63044 duk_context *ctx = (duk_context *) thr;
63045 duk_reg_t reg_varbind;
63046 duk_regconst_t rc_varname;
63047
63048 /* [ ... varname ] */
63049
63050 duk_dup_top(ctx);
63051 reg_varbind = duk__lookup_active_register_binding(comp_ctx);
63052
63053 if (reg_varbind >= 0) {
63054 *out_reg_varbind = reg_varbind;
63055 *out_rc_varname = 0; /* duk_regconst_t is unsigned, so use 0 as dummy value (ignored by caller) */
63056 duk_pop(ctx);
63057 return 1;
63058 } else {
63059 rc_varname = duk__getconst(comp_ctx);
63060 *out_reg_varbind = -1;
63061 *out_rc_varname = rc_varname;
63062 return 0;
63063 }
63064}
63065
63066/*
63067 * Label handling
63068 *
63069 * Labels are initially added with flags prohibiting both break and continue.
63070 * When the statement type is finally uncovered (after potentially multiple
63071 * labels), all the labels are updated to allow/prohibit break and continue.
63072 */
63073
63074DUK_LOCAL void duk__add_label(duk_compiler_ctx *comp_ctx, duk_hstring *h_label, duk_int_t pc_label, duk_int_t label_id) {
63075 duk_hthread *thr = comp_ctx->thr;
63076 duk_context *ctx = (duk_context *) thr;
63077 duk_size_t n;
63078 duk_size_t new_size;
63079 duk_uint8_t *p;
63080 duk_labelinfo *li_start, *li;
63081
63082 /* Duplicate (shadowing) labels are not allowed, except for the empty
63083 * labels (which are used as default labels for switch and iteration
63084 * statements).
63085 *
63086 * We could also allow shadowing of non-empty pending labels without any
63087 * other issues than breaking the required label shadowing requirements
63088 * of the E5 specification, see Section 12.12.
63089 */
63090
63091 p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos);
63092 li_start = (duk_labelinfo *) (void *) p;
63093 li = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
63094 n = (duk_size_t) (li - li_start);
63095
63096 while (li > li_start) {
63097 li--;
63098
63099 if (li->h_label == h_label && h_label != DUK_HTHREAD_STRING_EMPTY_STRING(thr)) {
63100 DUK_ERROR_SYNTAX(thr, DUK_STR_DUPLICATE_LABEL);
63101 }
63102 }
63103
63104 duk_push_hstring(ctx, h_label);
63105 DUK_ASSERT(n <= DUK_UARRIDX_MAX); /* label limits */
63106 (void) duk_put_prop_index(ctx, comp_ctx->curr_func.labelnames_idx, (duk_uarridx_t) n);
63107
63108 new_size = (n + 1) * sizeof(duk_labelinfo);
63109 duk_hbuffer_resize(thr, comp_ctx->curr_func.h_labelinfos, new_size);
63110 /* XXX: spare handling, slow now */
63111
63112 /* relookup after possible realloc */
63113 p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos);
63114 li_start = (duk_labelinfo *) (void *) p;
63115 DUK_UNREF(li_start); /* silence scan-build warning */
63116 li = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
63117 li--;
63118
63119 /* Labels can be used for iteration statements but also for other statements,
63120 * in particular a label can be used for a block statement. All cases of a
63121 * named label accept a 'break' so that flag is set here. Iteration statements
63122 * also allow 'continue', so that flag is updated when we figure out the
63123 * statement type.
63124 */
63125
63126 li->flags = DUK_LABEL_FLAG_ALLOW_BREAK;
63127 li->label_id = label_id;
63128 li->h_label = h_label;
63129 li->catch_depth = comp_ctx->curr_func.catch_depth; /* catch depth from current func */
63130 li->pc_label = pc_label;
63131
63132 DUK_DDD(DUK_DDDPRINT("registered label: flags=0x%08lx, id=%ld, name=%!O, catch_depth=%ld, pc_label=%ld",
63133 (unsigned long) li->flags, (long) li->label_id, (duk_heaphdr *) li->h_label,
63134 (long) li->catch_depth, (long) li->pc_label));
63135}
63136
63137/* Update all labels with matching label_id. */
63138DUK_LOCAL void duk__update_label_flags(duk_compiler_ctx *comp_ctx, duk_int_t label_id, duk_small_uint_t flags) {
63139 duk_uint8_t *p;
63140 duk_labelinfo *li_start, *li;
63141
63142 p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(comp_ctx->thr->heap, comp_ctx->curr_func.h_labelinfos);
63143 li_start = (duk_labelinfo *) (void *) p;
63144 li = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
63145
63146 /* Match labels starting from latest; once label_id no longer matches, we can
63147 * safely exit without checking the rest of the labels (only the topmost labels
63148 * are ever updated).
63149 */
63150 while (li > li_start) {
63151 li--;
63152
63153 if (li->label_id != label_id) {
63154 break;
63155 }
63156
63157 DUK_DDD(DUK_DDDPRINT("updating (overwriting) label flags for li=%p, label_id=%ld, flags=%ld",
63158 (void *) li, (long) label_id, (long) flags));
63159
63160 li->flags = flags;
63161 }
63162}
63163
63164/* Lookup active label information. Break/continue distinction is necessary to handle switch
63165 * statement related labels correctly: a switch will only catch a 'break', not a 'continue'.
63166 *
63167 * An explicit label cannot appear multiple times in the active set, but empty labels (unlabelled
63168 * iteration and switch statements) can. A break will match the closest unlabelled or labelled
63169 * statement. A continue will match the closest unlabelled or labelled iteration statement. It is
63170 * a syntax error if a continue matches a labelled switch statement; because an explicit label cannot
63171 * be duplicated, the continue cannot match any valid label outside the switch.
63172 *
63173 * A side effect of these rules is that a LABEL statement related to a switch should never actually
63174 * catch a continue abrupt completion at run-time. Hence an INVALID opcode can be placed in the
63175 * continue slot of the switch's LABEL statement.
63176 */
63177
63178/* XXX: awkward, especially the bunch of separate output values -> output struct? */
63179DUK_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) {
63180 duk_hthread *thr = comp_ctx->thr;
63181 duk_context *ctx = (duk_context *) thr;
63182 duk_uint8_t *p;
63183 duk_labelinfo *li_start, *li_end, *li;
63184 duk_bool_t match = 0;
63185
63186 DUK_DDD(DUK_DDDPRINT("looking up active label: label='%!O', is_break=%ld",
63187 (duk_heaphdr *) h_label, (long) is_break));
63188
63189 DUK_UNREF(ctx);
63190
63191 p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, comp_ctx->curr_func.h_labelinfos);
63192 li_start = (duk_labelinfo *) (void *) p;
63193 li_end = (duk_labelinfo *) (void *) (p + DUK_HBUFFER_GET_SIZE(comp_ctx->curr_func.h_labelinfos));
63194 li = li_end;
63195
63196 /* Match labels starting from latest label because there can be duplicate empty
63197 * labels in the label set.
63198 */
63199 while (li > li_start) {
63200 li--;
63201
63202 if (li->h_label != h_label) {
63203 DUK_DDD(DUK_DDDPRINT("labelinfo[%ld] ->'%!O' != %!O",
63204 (long) (li - li_start),
63205 (duk_heaphdr *) li->h_label,
63206 (duk_heaphdr *) h_label));
63207 continue;
63208 }
63209
63210 DUK_DDD(DUK_DDDPRINT("labelinfo[%ld] -> '%!O' label name matches (still need to check type)",
63211 (long) (li - li_start), (duk_heaphdr *) h_label));
63212
63213 /* currently all labels accept a break, so no explicit check for it now */
63214 DUK_ASSERT(li->flags & DUK_LABEL_FLAG_ALLOW_BREAK);
63215
63216 if (is_break) {
63217 /* break matches always */
63218 match = 1;
63219 break;
63220 } else if (li->flags & DUK_LABEL_FLAG_ALLOW_CONTINUE) {
63221 /* iteration statements allow continue */
63222 match = 1;
63223 break;
63224 } else {
63225 /* continue matched this label -- we can only continue if this is the empty
63226 * label, for which duplication is allowed, and thus there is hope of
63227 * finding a match deeper in the label stack.
63228 */
63229 if (h_label != DUK_HTHREAD_STRING_EMPTY_STRING(thr)) {
63230 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LABEL);
63231 } else {
63232 DUK_DDD(DUK_DDDPRINT("continue matched an empty label which does not "
63233 "allow a continue -> continue lookup deeper in label stack"));
63234 }
63235 }
63236 }
63237 /* XXX: match flag is awkward, rework */
63238 if (!match) {
63239 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LABEL);
63240 }
63241
63242 DUK_DDD(DUK_DDDPRINT("label match: %!O -> label_id %ld, catch_depth=%ld, pc_label=%ld",
63243 (duk_heaphdr *) h_label, (long) li->label_id,
63244 (long) li->catch_depth, (long) li->pc_label));
63245
63246 *out_label_id = li->label_id;
63247 *out_label_catch_depth = li->catch_depth;
63248 *out_label_pc = li->pc_label;
63249 *out_is_closest = (li == li_end - 1);
63250}
63251
63252DUK_LOCAL void duk__reset_labels_to_length(duk_compiler_ctx *comp_ctx, duk_int_t len) {
63253 duk_hthread *thr = comp_ctx->thr;
63254 duk_context *ctx = (duk_context *) thr;
63255
63256 duk_set_length(ctx, comp_ctx->curr_func.labelnames_idx, (duk_size_t) len);
63257 duk_hbuffer_resize(thr, comp_ctx->curr_func.h_labelinfos, sizeof(duk_labelinfo) * (duk_size_t) len);
63258}
63259
63260/*
63261 * Expression parsing: duk__expr_nud(), duk__expr_led(), duk__expr_lbp(), and helpers.
63262 *
63263 * - duk__expr_nud(): ("null denotation"): process prev_token as a "start" of an expression (e.g. literal)
63264 * - duk__expr_led(): ("left denotation"): process prev_token in the "middle" of an expression (e.g. operator)
63265 * - duk__expr_lbp(): ("left-binding power"): return left-binding power of curr_token
63266 */
63267
63268/* object literal key tracking flags */
63269#define DUK__OBJ_LIT_KEY_PLAIN (1 << 0) /* key encountered as a plain property */
63270#define DUK__OBJ_LIT_KEY_GET (1 << 1) /* key encountered as a getter */
63271#define DUK__OBJ_LIT_KEY_SET (1 << 2) /* key encountered as a setter */
63272
63273DUK_LOCAL void duk__nud_array_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
63274 duk_hthread *thr = comp_ctx->thr;
63275 duk_reg_t reg_obj; /* result reg */
63276 duk_reg_t reg_temp; /* temp reg */
63277 duk_reg_t temp_start; /* temp reg value for start of loop */
63278 duk_small_uint_t max_init_values; /* max # of values initialized in one MPUTARR set */
63279 duk_small_uint_t num_values; /* number of values in current MPUTARR set */
63280 duk_uarridx_t curr_idx; /* current (next) array index */
63281 duk_uarridx_t start_idx; /* start array index of current MPUTARR set */
63282 duk_uarridx_t init_idx; /* last array index explicitly initialized, +1 */
63283 duk_bool_t require_comma; /* next loop requires a comma */
63284
63285 /* DUK_TOK_LBRACKET already eaten, current token is right after that */
63286 DUK_ASSERT(comp_ctx->prev_token.t == DUK_TOK_LBRACKET);
63287
63288 max_init_values = DUK__MAX_ARRAY_INIT_VALUES; /* XXX: depend on available temps? */
63289
63290 reg_obj = DUK__ALLOCTEMP(comp_ctx);
63291 duk__emit_bc(comp_ctx, DUK_OP_NEWARR, reg_obj); /* XXX: patch initial size hint afterwards? */
63292 temp_start = DUK__GETTEMP(comp_ctx);
63293
63294 /*
63295 * Emit initializers in sets of maximum max_init_values.
63296 * Corner cases such as single value initializers do not have
63297 * special handling now.
63298 *
63299 * Elided elements must not be emitted as 'undefined' values,
63300 * because such values would be enumerable (which is incorrect).
63301 * Also note that trailing elisions must be reflected in the
63302 * length of the final array but cause no elements to be actually
63303 * inserted.
63304 */
63305
63306 curr_idx = 0;
63307 init_idx = 0; /* tracks maximum initialized index + 1 */
63308 start_idx = 0;
63309 require_comma = 0;
63310
63311 for (;;) {
63312 num_values = 0;
63313 DUK__SETTEMP(comp_ctx, temp_start);
63314
63315 if (comp_ctx->curr_token.t == DUK_TOK_RBRACKET) {
63316 break;
63317 }
63318
63319 for (;;) {
63320 if (comp_ctx->curr_token.t == DUK_TOK_RBRACKET) {
63321 /* the outer loop will recheck and exit */
63322 break;
63323 }
63324
63325 /* comma check */
63326 if (require_comma) {
63327 if (comp_ctx->curr_token.t == DUK_TOK_COMMA) {
63328 /* comma after a value, expected */
63329 duk__advance(comp_ctx);
63330 require_comma = 0;
63331 continue;
63332 } else {
63333 goto syntax_error;
63334 }
63335 } else {
63336 if (comp_ctx->curr_token.t == DUK_TOK_COMMA) {
63337 /* elision - flush */
63338 curr_idx++;
63339 duk__advance(comp_ctx);
63340 /* if num_values > 0, MPUTARR emitted by outer loop after break */
63341 break;
63342 }
63343 }
63344 /* else an array initializer element */
63345
63346 /* initial index */
63347 if (num_values == 0) {
63348 start_idx = curr_idx;
63349 reg_temp = DUK__ALLOCTEMP(comp_ctx);
63350 duk__emit_load_int32(comp_ctx, reg_temp, (duk_int32_t) start_idx);
63351 }
63352
63353 reg_temp = DUK__ALLOCTEMP(comp_ctx); /* alloc temp just in case, to update max temp */
63354 DUK__SETTEMP(comp_ctx, reg_temp);
63355 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/);
63356 DUK__SETTEMP(comp_ctx, reg_temp + 1);
63357
63358 num_values++;
63359 curr_idx++;
63360 require_comma = 1;
63361
63362 if (num_values >= max_init_values) {
63363 /* MPUTARR emitted by outer loop */
63364 break;
63365 }
63366 }
63367
63368 if (num_values > 0) {
63369 /* - A is a source register (it's not a write target, but used
63370 * to identify the target object) but can be shuffled.
63371 * - B cannot be shuffled normally because it identifies a range
63372 * of registers, the emitter has special handling for this
63373 * (the "no shuffle" flag must not be set).
63374 * - C is a non-register number and cannot be shuffled, but
63375 * never needs to be.
63376 */
63377 duk__emit_a_b_c(comp_ctx,
63378 DUK_OP_MPUTARR |
63379 DUK__EMIT_FLAG_NO_SHUFFLE_C |
63380 DUK__EMIT_FLAG_A_IS_SOURCE,
63381 (duk_regconst_t) reg_obj,
63382 (duk_regconst_t) temp_start,
63383 (duk_regconst_t) (num_values + 1));
63384 init_idx = start_idx + num_values;
63385
63386 /* num_values and temp_start reset at top of outer loop */
63387 }
63388 }
63389
63390 DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RBRACKET);
63391 duk__advance(comp_ctx);
63392
63393 DUK_DDD(DUK_DDDPRINT("array literal done, curridx=%ld, initidx=%ld",
63394 (long) curr_idx, (long) init_idx));
63395
63396 /* trailing elisions? */
63397 if (curr_idx > init_idx) {
63398 /* yes, must set array length explicitly */
63399 DUK_DDD(DUK_DDDPRINT("array literal has trailing elisions which affect its length"));
63400 reg_temp = DUK__ALLOCTEMP(comp_ctx);
63401 duk__emit_load_int32(comp_ctx, reg_temp, (duk_int_t) curr_idx);
63402 duk__emit_a_bc(comp_ctx,
63403 DUK_OP_SETALEN | DUK__EMIT_FLAG_A_IS_SOURCE,
63404 (duk_regconst_t) reg_obj,
63405 (duk_regconst_t) reg_temp);
63406 }
63407
63408 DUK__SETTEMP(comp_ctx, temp_start);
63409
63410 duk__ivalue_regconst(res, (duk_regconst_t) reg_obj);
63411 return;
63412
63413 syntax_error:
63414 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_ARRAY_LITERAL);
63415}
63416
63417typedef struct {
63418 duk_reg_t reg_obj;
63419 duk_reg_t temp_start;
63420 duk_small_uint_t num_pairs;
63422
63423DUK_LOCAL void duk__objlit_flush_keys(duk_compiler_ctx *comp_ctx, duk__objlit_state *st) {
63424 if (st->num_pairs > 0) {
63425 /* - A is a source register (it's not a write target, but used
63426 * to identify the target object) but can be shuffled.
63427 * - B cannot be shuffled normally because it identifies a range
63428 * of registers, the emitter has special handling for this
63429 * (the "no shuffle" flag must not be set).
63430 * - C is a non-register number and cannot be shuffled, but
63431 * never needs to be.
63432 */
63433 DUK_ASSERT(st->num_pairs > 0);
63434 duk__emit_a_b_c(comp_ctx,
63435 DUK_OP_MPUTOBJ |
63436 DUK__EMIT_FLAG_NO_SHUFFLE_C |
63437 DUK__EMIT_FLAG_A_IS_SOURCE,
63438 st->reg_obj,
63439 st->temp_start,
63440 st->num_pairs * 2);
63441 st->num_pairs = 0;
63442 }
63443 DUK__SETTEMP(comp_ctx, st->temp_start);
63444}
63445
63446DUK_LOCAL duk_bool_t duk__objlit_load_key(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_token *tok, duk_reg_t reg_temp) {
63447 if (tok->t_nores == DUK_TOK_IDENTIFIER || tok->t_nores == DUK_TOK_STRING) {
63448 /* same handling for identifiers and strings */
63449 DUK_ASSERT(tok->str1 != NULL);
63450 duk_push_hstring((duk_context *) comp_ctx->thr, tok->str1);
63451 } else if (tok->t == DUK_TOK_NUMBER) {
63452 /* numbers can be loaded as numbers and coerced on the fly */
63453 duk_push_number((duk_context *) comp_ctx->thr, tok->num);
63454 } else {
63455 return 1; /* error */
63456 }
63457
63458 duk__ivalue_plain_fromstack(comp_ctx, res);
63459 DUK__SETTEMP(comp_ctx, reg_temp + 1);
63460 duk__ivalue_toforcedreg(comp_ctx, res, reg_temp);
63461 DUK__SETTEMP(comp_ctx, reg_temp + 1);
63462 return 0;
63463}
63464
63465DUK_LOCAL void duk__nud_object_literal(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
63466 duk_hthread *thr = comp_ctx->thr;
63468 duk_reg_t reg_temp; /* temp reg */
63469 duk_small_uint_t max_init_pairs; /* max # of key-value pairs initialized in one MPUTOBJ set */
63470 duk_bool_t first; /* first value: comma must not precede the value */
63471 duk_bool_t is_set, is_get; /* temps */
63472
63473 DUK_ASSERT(comp_ctx->prev_token.t == DUK_TOK_LCURLY);
63474
63475 max_init_pairs = DUK__MAX_OBJECT_INIT_PAIRS; /* XXX: depend on available temps? */
63476
63477 st.reg_obj = DUK__ALLOCTEMP(comp_ctx); /* target object */
63478 st.temp_start = DUK__GETTEMP(comp_ctx); /* start of MPUTOBJ argument list */
63479 st.num_pairs = 0; /* number of key/value pairs emitted for current MPUTOBJ set */
63480
63481 duk__emit_bc(comp_ctx, DUK_OP_NEWOBJ, st.reg_obj); /* XXX: patch initial size hint afterwards? */
63482
63483 /*
63484 * Emit initializers in sets of maximum max_init_pairs keys.
63485 * Setter/getter is handled separately and terminates the
63486 * current set of initializer values. Corner cases such as
63487 * single value initializers do not have special handling now.
63488 */
63489
63490 first = 1;
63491 for (;;) {
63492 /*
63493 * ES5 and ES2015+ provide a lot of different PropertyDefinition
63494 * formats, see http://www.ecma-international.org/ecma-262/6.0/#sec-object-initializer.
63495 *
63496 * PropertyName can be IdentifierName (includes reserved words), a string
63497 * literal, or a number literal. Note that IdentifierName allows 'get' and
63498 * 'set' too, so we need to look ahead to the next token to distinguish:
63499 *
63500 * { get : 1 }
63501 *
63502 * and
63503 *
63504 * { get foo() { return 1 } }
63505 * { get get() { return 1 } } // 'get' as getter propertyname
63506 *
63507 * Finally, a trailing comma is allowed.
63508 *
63509 * Key name is coerced to string at compile time (and ends up as a
63510 * a string constant) even for numeric keys (e.g. "{1:'foo'}").
63511 * These could be emitted using e.g. LDINT, but that seems hardly
63512 * worth the effort and would increase code size.
63513 */
63514
63515 DUK_DDD(DUK_DDDPRINT("object literal loop, curr_token->t = %ld",
63516 (long) comp_ctx->curr_token.t));
63517
63518 if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
63519 break;
63520 }
63521
63522 if (first) {
63523 first = 0;
63524 } else {
63525 if (comp_ctx->curr_token.t != DUK_TOK_COMMA) {
63526 goto syntax_error;
63527 }
63528 duk__advance(comp_ctx);
63529 if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
63530 /* trailing comma followed by rcurly */
63531 break;
63532 }
63533 }
63534
63535 /* Advance to get one step of lookup. */
63536 duk__advance(comp_ctx);
63537
63538 /* Flush current MPUTOBJ if enough many pairs gathered. */
63539 if (st.num_pairs >= max_init_pairs) {
63540 duk__objlit_flush_keys(comp_ctx, &st);
63541 DUK_ASSERT(st.num_pairs == 0);
63542 }
63543
63544 /* Reset temp register state and reserve reg_temp and
63545 * reg_temp + 1 for handling the current property.
63546 */
63547 DUK__SETTEMP(comp_ctx, st.temp_start + 2 * st.num_pairs);
63548 reg_temp = DUK__ALLOCTEMPS(comp_ctx, 2);
63549
63550 /* NOTE: "get" and "set" are not officially ReservedWords and the lexer
63551 * currently treats them always like ordinary identifiers (DUK_TOK_GET
63552 * and DUK_TOK_SET are unused). They need to be detected based on the
63553 * identifier string content.
63554 */
63555
63556 is_get = (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
63557 comp_ctx->prev_token.str1 == DUK_HTHREAD_STRING_GET(thr));
63558 is_set = (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
63559 comp_ctx->prev_token.str1 == DUK_HTHREAD_STRING_SET(thr));
63560 if ((is_get || is_set) && comp_ctx->curr_token.t != DUK_TOK_COLON) {
63561 /* getter/setter */
63562 duk_int_t fnum;
63563
63564 duk__objlit_flush_keys(comp_ctx, &st);
63565 DUK_ASSERT(DUK__GETTEMP(comp_ctx) == st.temp_start); /* 2 regs are guaranteed to be allocated w.r.t. temp_max */
63566 reg_temp = DUK__ALLOCTEMPS(comp_ctx, 2);
63567
63568 if (duk__objlit_load_key(comp_ctx, res, &comp_ctx->curr_token, reg_temp) != 0) {
63569 goto syntax_error;
63570 }
63571
63572 /* curr_token = get/set name */
63573 fnum = duk__parse_func_like_fnum(comp_ctx, DUK__FUNC_FLAG_GETSET);
63574
63575 duk__emit_a_bc(comp_ctx,
63576 DUK_OP_CLOSURE,
63577 (duk_regconst_t) (st.temp_start + 1),
63578 (duk_regconst_t) fnum);
63579
63580 /* Slot C is used in a non-standard fashion (range of regs),
63581 * emitter code has special handling for it (must not set the
63582 * "no shuffle" flag).
63583 */
63584 duk__emit_a_bc(comp_ctx,
63585 (is_get ? DUK_OP_INITGET : DUK_OP_INITSET) | DUK__EMIT_FLAG_A_IS_SOURCE,
63586 st.reg_obj,
63587 st.temp_start); /* temp_start+0 = key, temp_start+1 = closure */
63588
63589 DUK_ASSERT(st.num_pairs == 0); /* temp state is reset on next loop */
63590#if defined(DUK_USE_ES6)
63591 } else if (comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
63592 (comp_ctx->curr_token.t == DUK_TOK_COMMA || comp_ctx->curr_token.t == DUK_TOK_RCURLY)) {
63593 duk_bool_t load_rc;
63594
63595 load_rc = duk__objlit_load_key(comp_ctx, res, &comp_ctx->prev_token, reg_temp);
63596 DUK_UNREF(load_rc);
63597 DUK_ASSERT(load_rc == 0); /* always succeeds because token is identifier */
63598
63599 duk__ivalue_var_hstring(comp_ctx, res, comp_ctx->prev_token.str1);
63600 DUK_ASSERT(DUK__GETTEMP(comp_ctx) == reg_temp + 1);
63601 duk__ivalue_toforcedreg(comp_ctx, res, reg_temp + 1);
63602
63603 st.num_pairs++;
63604 } else if ((comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER ||
63605 comp_ctx->prev_token.t == DUK_TOK_STRING ||
63606 comp_ctx->prev_token.t == DUK_TOK_NUMBER) &&
63607 comp_ctx->curr_token.t == DUK_TOK_LPAREN) {
63608 duk_int_t fnum;
63609
63610 /* Parsing-wise there's a small hickup here: the token parsing
63611 * state is one step too advanced for the function parse helper
63612 * compared to other cases. The current solution is an extra
63613 * flag to indicate whether function parsing should use the
63614 * current or the previous token to starting parsing from.
63615 */
63616
63617 if (duk__objlit_load_key(comp_ctx, res, &comp_ctx->prev_token, reg_temp) != 0) {
63618 goto syntax_error;
63619 }
63620
63621 fnum = duk__parse_func_like_fnum(comp_ctx, DUK__FUNC_FLAG_USE_PREVTOKEN | DUK__FUNC_FLAG_METDEF);
63622
63623 duk__emit_a_bc(comp_ctx,
63624 DUK_OP_CLOSURE,
63625 (duk_regconst_t) (reg_temp + 1),
63626 (duk_regconst_t) fnum);
63627
63628 st.num_pairs++;
63629#endif /* DUK_USE_ES6 */
63630 } else {
63631#if defined(DUK_USE_ES6)
63632 if (comp_ctx->prev_token.t == DUK_TOK_LBRACKET) {
63633 /* ES2015 computed property name. Executor ToPropertyKey()
63634 * coerces the key at runtime.
63635 */
63636 DUK__SETTEMP(comp_ctx, reg_temp);
63637 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_FOR_EXPR, reg_temp);
63638 duk__advance_expect(comp_ctx, DUK_TOK_RBRACKET);
63639
63640 /* XXX: If next token is '(' we're dealing with
63641 * the method shorthand with a computed name,
63642 * e.g. { [Symbol.for('foo')](a,b) {} }. This
63643 * form is not yet supported and causes a
63644 * SyntaxError on the DUK_TOK_COLON check below.
63645 */
63646 }
63647 else
63648#endif /* DUK_USE_ES6 */
63649 {
63650 if (duk__objlit_load_key(comp_ctx, res, &comp_ctx->prev_token, reg_temp) != 0) {
63651 goto syntax_error;
63652 }
63653 }
63654
63655 duk__advance_expect(comp_ctx, DUK_TOK_COLON);
63656
63657 DUK__SETTEMP(comp_ctx, reg_temp + 1);
63658 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp + 1 /*forced_reg*/);
63659
63660 st.num_pairs++;
63661 }
63662 } /* property loop */
63663
63664 /* Flush remaining properties. */
63665 duk__objlit_flush_keys(comp_ctx, &st);
63666 DUK_ASSERT(st.num_pairs == 0);
63667 DUK_ASSERT(DUK__GETTEMP(comp_ctx) == st.temp_start);
63668
63669 DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RCURLY);
63670 duk__advance(comp_ctx);
63671
63672 duk__ivalue_regconst(res, (duk_regconst_t) st.reg_obj);
63673 return;
63674
63675 syntax_error:
63676 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_OBJECT_LITERAL);
63677}
63678
63679/* Parse argument list. Arguments are written to temps starting from
63680 * "next temp". Returns number of arguments parsed. Expects left paren
63681 * to be already eaten, and eats the right paren before returning.
63682 */
63683DUK_LOCAL duk_int_t duk__parse_arguments(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
63684 duk_int_t nargs = 0;
63685 duk_reg_t reg_temp;
63686
63687 /* Note: expect that caller has already eaten the left paren */
63688
63689 DUK_DDD(DUK_DDDPRINT("start parsing arguments, prev_token.t=%ld, curr_token.t=%ld",
63690 (long) comp_ctx->prev_token.t, (long) comp_ctx->curr_token.t));
63691
63692 for (;;) {
63693 if (comp_ctx->curr_token.t == DUK_TOK_RPAREN) {
63694 break;
63695 }
63696 if (nargs > 0) {
63697 duk__advance_expect(comp_ctx, DUK_TOK_COMMA);
63698 }
63699
63700 /* We want the argument expression value to go to "next temp"
63701 * without additional moves. That should almost always be the
63702 * case, but we double check after expression parsing.
63703 *
63704 * This is not the cleanest possible approach.
63705 */
63706
63707 reg_temp = DUK__ALLOCTEMP(comp_ctx); /* bump up "allocated" reg count, just in case */
63708 DUK__SETTEMP(comp_ctx, reg_temp);
63709
63710 /* binding power must be high enough to NOT allow comma expressions directly */
63711 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp); /* always allow 'in', coerce to 'tr' just in case */
63712
63713 DUK__SETTEMP(comp_ctx, reg_temp + 1);
63714 nargs++;
63715
63716 DUK_DDD(DUK_DDDPRINT("argument #%ld written into reg %ld", (long) nargs, (long) reg_temp));
63717 }
63718
63719 /* eat the right paren */
63720 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
63721
63722 DUK_DDD(DUK_DDDPRINT("end parsing arguments"));
63723
63724 return nargs;
63725}
63726
63727DUK_LOCAL duk_bool_t duk__expr_is_empty(duk_compiler_ctx *comp_ctx) {
63728 /* empty expressions can be detected conveniently with nud/led counts */
63729 return (comp_ctx->curr_func.nud_count == 0) &&
63730 (comp_ctx->curr_func.led_count == 0);
63731}
63732
63733DUK_LOCAL void duk__expr_nud(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
63734 duk_hthread *thr = comp_ctx->thr;
63735 duk_context *ctx = (duk_context *) thr;
63736 duk_token *tk;
63737 duk_reg_t temp_at_entry;
63738 duk_small_int_t tok;
63739 duk_uint32_t args; /* temp variable to pass constants and flags to shared code */
63740
63741 /*
63742 * ctx->prev_token token to process with duk__expr_nud()
63743 * ctx->curr_token updated by caller
63744 *
63745 * Note: the token in the switch below has already been eaten.
63746 */
63747
63748 temp_at_entry = DUK__GETTEMP(comp_ctx);
63749
63750 comp_ctx->curr_func.nud_count++;
63751
63752 tk = &comp_ctx->prev_token;
63753 tok = tk->t;
63754 res->t = DUK_IVAL_NONE;
63755
63756 DUK_DDD(DUK_DDDPRINT("duk__expr_nud(), prev_token.t=%ld, allow_in=%ld, paren_level=%ld",
63757 (long) tk->t, (long) comp_ctx->curr_func.allow_in, (long) comp_ctx->curr_func.paren_level));
63758
63759 switch (tok) {
63760
63761 /* PRIMARY EXPRESSIONS */
63762
63763 case DUK_TOK_THIS: {
63764 duk_reg_t reg_temp;
63765 reg_temp = DUK__ALLOCTEMP(comp_ctx);
63766 duk__emit_bc(comp_ctx,
63767 DUK_OP_LDTHIS,
63768 (duk_regconst_t) reg_temp);
63769 duk__ivalue_regconst(res, (duk_regconst_t) reg_temp);
63770 return;
63771 }
63772 case DUK_TOK_IDENTIFIER: {
63773 duk__ivalue_var_hstring(comp_ctx, res, tk->str1);
63774 return;
63775 }
63776 case DUK_TOK_NULL: {
63777 duk_push_null(ctx);
63778 goto plain_value;
63779 }
63780 case DUK_TOK_TRUE: {
63781 duk_push_true(ctx);
63782 goto plain_value;
63783 }
63784 case DUK_TOK_FALSE: {
63785 duk_push_false(ctx);
63786 goto plain_value;
63787 }
63788 case DUK_TOK_NUMBER: {
63789 duk_push_number(ctx, tk->num);
63790 goto plain_value;
63791 }
63792 case DUK_TOK_STRING: {
63793 DUK_ASSERT(tk->str1 != NULL);
63794 duk_push_hstring(ctx, tk->str1);
63795 goto plain_value;
63796 }
63797 case DUK_TOK_REGEXP: {
63798#if defined(DUK_USE_REGEXP_SUPPORT)
63799 duk_reg_t reg_temp;
63800 duk_regconst_t rc_re_bytecode; /* const */
63801 duk_regconst_t rc_re_source; /* const */
63802
63803 DUK_ASSERT(tk->str1 != NULL);
63804 DUK_ASSERT(tk->str2 != NULL);
63805
63806 DUK_DDD(DUK_DDDPRINT("emitting regexp op, str1=%!O, str2=%!O",
63807 (duk_heaphdr *) tk->str1,
63808 (duk_heaphdr *) tk->str2));
63809
63810 reg_temp = DUK__ALLOCTEMP(comp_ctx);
63811 duk_push_hstring(ctx, tk->str1);
63812 duk_push_hstring(ctx, tk->str2);
63813
63814 /* [ ... pattern flags ] */
63815
63816 duk_regexp_compile(thr);
63817
63818 /* [ ... escaped_source bytecode ] */
63819
63820 rc_re_bytecode = duk__getconst(comp_ctx);
63821 rc_re_source = duk__getconst(comp_ctx);
63822
63823 duk__emit_a_b_c(comp_ctx,
63824 DUK_OP_REGEXP | DUK__EMIT_FLAG_BC_REGCONST,
63825 (duk_regconst_t) reg_temp /*a*/,
63826 rc_re_bytecode /*b*/,
63827 rc_re_source /*c*/);
63828
63829 duk__ivalue_regconst(res, (duk_regconst_t) reg_temp);
63830 return;
63831#else /* DUK_USE_REGEXP_SUPPORT */
63832 goto syntax_error;
63833#endif /* DUK_USE_REGEXP_SUPPORT */
63834 }
63835 case DUK_TOK_LBRACKET: {
63836 DUK_DDD(DUK_DDDPRINT("parsing array literal"));
63837 duk__nud_array_literal(comp_ctx, res);
63838 return;
63839 }
63840 case DUK_TOK_LCURLY: {
63841 DUK_DDD(DUK_DDDPRINT("parsing object literal"));
63842 duk__nud_object_literal(comp_ctx, res);
63843 return;
63844 }
63845 case DUK_TOK_LPAREN: {
63846 duk_bool_t prev_allow_in;
63847
63848 comp_ctx->curr_func.paren_level++;
63849 prev_allow_in = comp_ctx->curr_func.allow_in;
63850 comp_ctx->curr_func.allow_in = 1; /* reset 'allow_in' for parenthesized expression */
63851
63852 duk__expr(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); /* Expression, terminates at a ')' */
63853
63854 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
63855 comp_ctx->curr_func.allow_in = prev_allow_in;
63856 comp_ctx->curr_func.paren_level--;
63857 return;
63858 }
63859
63860 /* MEMBER/NEW/CALL EXPRESSIONS */
63861
63862 case DUK_TOK_NEW: {
63863 /*
63864 * Parsing an expression starting with 'new' is tricky because
63865 * there are multiple possible productions deriving from
63866 * LeftHandSideExpression which begin with 'new'.
63867 *
63868 * We currently resort to one-token lookahead to distinguish the
63869 * cases. Hopefully this is correct. The binding power must be
63870 * such that parsing ends at an LPAREN (CallExpression) but not at
63871 * a PERIOD or LBRACKET (MemberExpression).
63872 *
63873 * See doc/compiler.rst for discussion on the parsing approach,
63874 * and testcases/test-dev-new.js for a bunch of documented tests.
63875 */
63876
63877 duk_reg_t reg_target;
63878 duk_int_t nargs;
63879
63880 DUK_DDD(DUK_DDDPRINT("begin parsing new expression"));
63881
63882 reg_target = DUK__ALLOCTEMP(comp_ctx);
63883 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_CALL /*rbp_flags*/, reg_target /*forced_reg*/);
63884 DUK__SETTEMP(comp_ctx, reg_target + 1);
63885
63886 if (comp_ctx->curr_token.t == DUK_TOK_LPAREN) {
63887 /* 'new' MemberExpression Arguments */
63888 DUK_DDD(DUK_DDDPRINT("new expression has argument list"));
63889 duk__advance(comp_ctx);
63890 nargs = duk__parse_arguments(comp_ctx, res); /* parse args starting from "next temp", reg_target + 1 */
63891 /* right paren eaten */
63892 } else {
63893 /* 'new' MemberExpression */
63894 DUK_DDD(DUK_DDDPRINT("new expression has no argument list"));
63895 nargs = 0;
63896 }
63897
63898 /* Opcode slot C is used in a non-standard way, so shuffling
63899 * is not allowed.
63900 */
63901 duk__emit_a_bc(comp_ctx,
63902 DUK_OP_NEW | DUK__EMIT_FLAG_NO_SHUFFLE_A,
63903 nargs /*num_args*/,
63904 reg_target /*target*/);
63905
63906 DUK_DDD(DUK_DDDPRINT("end parsing new expression"));
63907
63908 duk__ivalue_regconst(res, (duk_regconst_t) reg_target);
63909 return;
63910 }
63911
63912 /* FUNCTION EXPRESSIONS */
63913
63914 case DUK_TOK_FUNCTION: {
63915 /* Function expression. Note that any statement beginning with 'function'
63916 * is handled by the statement parser as a function declaration, or a
63917 * non-standard function expression/statement (or a SyntaxError). We only
63918 * handle actual function expressions (occurring inside an expression) here.
63919 *
63920 * O(depth^2) parse count for inner functions is handled by recording a
63921 * lexer offset on the first compilation pass, so that the function can
63922 * be efficiently skipped on the second pass. This is encapsulated into
63923 * duk__parse_func_like_fnum().
63924 */
63925
63926 duk_reg_t reg_temp;
63927 duk_int_t fnum;
63928
63929 reg_temp = DUK__ALLOCTEMP(comp_ctx);
63930
63931 /* curr_token follows 'function' */
63932 fnum = duk__parse_func_like_fnum(comp_ctx, 0 /*flags*/);
63933 DUK_DDD(DUK_DDDPRINT("parsed inner function -> fnum %ld", (long) fnum));
63934
63935 duk__emit_a_bc(comp_ctx,
63936 DUK_OP_CLOSURE,
63937 (duk_regconst_t) reg_temp /*a*/,
63938 (duk_regconst_t) fnum /*bc*/);
63939
63940 duk__ivalue_regconst(res, (duk_regconst_t) reg_temp);
63941 return;
63942 }
63943
63944 /* UNARY EXPRESSIONS */
63945
63946 case DUK_TOK_DELETE: {
63947 /* Delete semantics are a bit tricky. The description in E5 specification
63948 * is kind of confusing, because it distinguishes between resolvability of
63949 * a reference (which is only known at runtime) seemingly at compile time
63950 * (= SyntaxError throwing).
63951 */
63952 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
63953 if (res->t == DUK_IVAL_VAR) {
63954 /* not allowed in strict mode, regardless of whether resolves;
63955 * in non-strict mode DELVAR handles both non-resolving and
63956 * resolving cases (the specification description is a bit confusing).
63957 */
63958
63959 duk_reg_t reg_temp;
63960 duk_reg_t reg_varbind;
63961 duk_regconst_t rc_varname;
63962
63963 if (comp_ctx->curr_func.is_strict) {
63964 DUK_ERROR_SYNTAX(thr, DUK_STR_CANNOT_DELETE_IDENTIFIER);
63965 }
63966
63967 DUK__SETTEMP(comp_ctx, temp_at_entry);
63968 reg_temp = DUK__ALLOCTEMP(comp_ctx);
63969
63970 duk_dup(ctx, res->x1.valstack_idx);
63971 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
63972 /* register bound variables are non-configurable -> always false */
63973 duk__emit_bc(comp_ctx,
63974 DUK_OP_LDFALSE,
63975 (duk_regconst_t) reg_temp);
63976 } else {
63977 duk_dup(ctx, res->x1.valstack_idx);
63978 rc_varname = duk__getconst(comp_ctx);
63979 duk__emit_a_bc(comp_ctx,
63980 DUK_OP_DELVAR,
63981 (duk_regconst_t) reg_temp,
63982 (duk_regconst_t) rc_varname);
63983 }
63984 duk__ivalue_regconst(res, (duk_regconst_t) reg_temp);
63985 } else if (res->t == DUK_IVAL_PROP) {
63986 duk_reg_t reg_temp;
63987 duk_reg_t reg_obj;
63988 duk_regconst_t rc_key;
63989
63990 DUK__SETTEMP(comp_ctx, temp_at_entry);
63991 reg_temp = DUK__ALLOCTEMP(comp_ctx);
63992 reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
63993 rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
63994 duk__emit_a_b_c(comp_ctx,
63995 DUK_OP_DELPROP | DUK__EMIT_FLAG_BC_REGCONST,
63996 (duk_regconst_t) reg_temp,
63997 (duk_regconst_t) reg_obj,
63998 rc_key);
63999
64000 duk__ivalue_regconst(res, (duk_regconst_t) reg_temp);
64001 } else {
64002 /* non-Reference deletion is always 'true', even in strict mode */
64003 duk_push_true(ctx);
64004 goto plain_value;
64005 }
64006 return;
64007 }
64008 case DUK_TOK_VOID: {
64009 duk__expr_toplain_ignore(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
64010 duk_push_undefined(ctx);
64011 goto plain_value;
64012 }
64013 case DUK_TOK_TYPEOF: {
64014 /* 'typeof' must handle unresolvable references without throwing
64015 * a ReferenceError (E5 Section 11.4.3). Register mapped values
64016 * will never be unresolvable so special handling is only required
64017 * when an identifier is a "slow path" one.
64018 */
64019 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
64020
64021 if (res->t == DUK_IVAL_VAR) {
64022 duk_reg_t reg_varbind;
64023 duk_regconst_t rc_varname;
64024 duk_reg_t reg_temp;
64025
64026 duk_dup(ctx, res->x1.valstack_idx);
64027 if (!duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
64028 DUK_DDD(DUK_DDDPRINT("typeof for an identifier name which could not be resolved "
64029 "at compile time, need to use special run-time handling"));
64030 reg_temp = DUK__ALLOCTEMP(comp_ctx);
64031 duk__emit_a_bc(comp_ctx,
64032 DUK_OP_TYPEOFID,
64033 reg_temp,
64034 rc_varname);
64035 duk__ivalue_regconst(res, (duk_regconst_t) reg_temp);
64036 return;
64037 }
64038 }
64039
64040 args = DUK_OP_TYPEOF;
64041 goto unary;
64042 }
64043 case DUK_TOK_INCREMENT: {
64044 args = (DUK_OP_PREINCP << 8) + DUK_OP_PREINCR;
64045 goto preincdec;
64046 }
64047 case DUK_TOK_DECREMENT: {
64048 args = (DUK_OP_PREDECP << 8) + DUK_OP_PREDECR;
64049 goto preincdec;
64050 }
64051 case DUK_TOK_ADD: {
64052 /* unary plus */
64053 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
64054 if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE &&
64055 duk_is_number(ctx, res->x1.valstack_idx)) {
64056 /* unary plus of a number is identity */
64057 return;
64058 }
64059 args = DUK_OP_UNP;
64060 goto unary;
64061 }
64062 case DUK_TOK_SUB: {
64063 /* unary minus */
64064 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
64065 if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE &&
64066 duk_is_number(ctx, res->x1.valstack_idx)) {
64067 /* this optimization is important to handle negative literals
64068 * (which are not directly provided by the lexical grammar)
64069 */
64070 duk_tval *tv_num;
64072
64073 tv_num = DUK_GET_TVAL_POSIDX(ctx, res->x1.valstack_idx);
64074 DUK_ASSERT(tv_num != NULL);
64075 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_num));
64076 du.d = DUK_TVAL_GET_NUMBER(tv_num);
64077 du.d = -du.d;
64078 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
64079 DUK_TVAL_SET_NUMBER(tv_num, du.d);
64080 return;
64081 }
64082 args = DUK_OP_UNM;
64083 goto unary;
64084 }
64085 case DUK_TOK_BNOT: {
64086 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
64087 args = DUK_OP_BNOT;
64088 goto unary;
64089 }
64090 case DUK_TOK_LNOT: {
64091 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
64092 if (res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_VALUE) {
64093 /* Very minimal inlining to handle common idioms '!0' and '!1',
64094 * and also boolean arguments like '!false' and '!true'.
64095 */
64096 duk_tval *tv_val;
64097
64098 tv_val = DUK_GET_TVAL_POSIDX(ctx, res->x1.valstack_idx);
64099 DUK_ASSERT(tv_val != NULL);
64100 if (DUK_TVAL_IS_NUMBER(tv_val)) {
64101 duk_double_t d;
64102 d = DUK_TVAL_GET_NUMBER(tv_val);
64103 if (d == 0.0) {
64104 /* Matches both +0 and -0 on purpose. */
64105 DUK_DDD(DUK_DDDPRINT("inlined lnot: !0 -> true"));
64106 DUK_TVAL_SET_BOOLEAN_TRUE(tv_val);
64107 return;
64108 } else if (d == 1.0) {
64109 DUK_DDD(DUK_DDDPRINT("inlined lnot: !1 -> false"));
64110 DUK_TVAL_SET_BOOLEAN_FALSE(tv_val);
64111 return;
64112 }
64113 } else if (DUK_TVAL_IS_BOOLEAN(tv_val)) {
64114 duk_small_int_t v;
64115 v = DUK_TVAL_GET_BOOLEAN(tv_val);
64116 DUK_DDD(DUK_DDDPRINT("inlined lnot boolean: %ld", (long) v));
64117 DUK_ASSERT(v == 0 || v == 1);
64118 DUK_TVAL_SET_BOOLEAN(tv_val, v ^ 0x01);
64119 return;
64120 }
64121 }
64122 args = DUK_OP_LNOT;
64123 goto unary;
64124 }
64125
64126 } /* end switch */
64127
64128 DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR);
64129 return;
64130
64131 unary:
64132 {
64133 /* Unary opcodes use just the 'BC' register source because it
64134 * matches current shuffle limits, and maps cleanly to 16 high
64135 * bits of the opcode.
64136 */
64137
64138 duk_reg_t reg_src, reg_res;
64139
64140 reg_src = duk__ivalue_toregconst_raw(comp_ctx, res, -1 /*forced_reg*/, 0 /*flags*/);
64141 if (DUK__ISTEMP(comp_ctx, reg_src)) {
64142 reg_res = reg_src;
64143 } else {
64144 reg_res = DUK__ALLOCTEMP(comp_ctx);
64145 }
64146 duk__emit_a_bc(comp_ctx,
64147 args,
64148 reg_res,
64149 (duk_regconst_t) reg_src);
64150 duk__ivalue_regconst(res, (duk_regconst_t) reg_res);
64151 return;
64152 }
64153
64154 preincdec:
64155 {
64156 /* preincrement and predecrement */
64157 duk_reg_t reg_res;
64158 duk_small_uint_t args_op1 = args & 0xff; /* DUK_OP_PREINCR/DUK_OP_PREDECR */
64159 duk_small_uint_t args_op2 = args >> 8; /* DUK_OP_PREINCP_RR/DUK_OP_PREDECP_RR */
64160
64161 /* Specific assumptions for opcode numbering. */
64162 DUK_ASSERT(DUK_OP_PREINCR + 4 == DUK_OP_PREINCV);
64163 DUK_ASSERT(DUK_OP_PREDECR + 4 == DUK_OP_PREDECV);
64164
64165 reg_res = DUK__ALLOCTEMP(comp_ctx);
64166
64167 duk__expr(comp_ctx, res, DUK__BP_MULTIPLICATIVE /*rbp_flags*/); /* UnaryExpression */
64168 if (res->t == DUK_IVAL_VAR) {
64169 duk_hstring *h_varname;
64170 duk_reg_t reg_varbind;
64171 duk_regconst_t rc_varname;
64172
64173 h_varname = duk_known_hstring(ctx, res->x1.valstack_idx);
64174
64175 if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
64176 goto syntax_error;
64177 }
64178
64179 duk_dup(ctx, res->x1.valstack_idx);
64180 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
64181 duk__emit_a_bc(comp_ctx,
64182 args_op1, /* e.g. DUK_OP_PREINCR */
64183 (duk_regconst_t) reg_res,
64184 (duk_regconst_t) reg_varbind);
64185 } else {
64186 duk__emit_a_bc(comp_ctx,
64187 args_op1 + 4, /* e.g. DUK_OP_PREINCV */
64188 (duk_regconst_t) reg_res,
64189 rc_varname);
64190 }
64191
64192 DUK_DDD(DUK_DDDPRINT("preincdec to '%!O' -> reg_varbind=%ld, rc_varname=%ld",
64193 (duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname));
64194 } else if (res->t == DUK_IVAL_PROP) {
64195 duk_reg_t reg_obj; /* allocate to reg only (not const) */
64196 duk_regconst_t rc_key;
64197 reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
64198 rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
64199 duk__emit_a_b_c(comp_ctx,
64200 args_op2 | DUK__EMIT_FLAG_BC_REGCONST, /* e.g. DUK_OP_PREINCP */
64201 (duk_regconst_t) reg_res,
64202 (duk_regconst_t) reg_obj,
64203 rc_key);
64204 } else {
64205 /* Technically return value is not needed because INVLHS will
64206 * unconditially throw a ReferenceError. Coercion is necessary
64207 * for proper semantics (consider ToNumber() called for an object).
64208 * Use DUK_OP_UNP with a dummy register to get ToNumber().
64209 */
64210
64211 duk__ivalue_toforcedreg(comp_ctx, res, reg_res);
64212 duk__emit_bc(comp_ctx,
64213 DUK_OP_UNP,
64214 reg_res); /* for side effects, result ignored */
64215 duk__emit_op_only(comp_ctx,
64216 DUK_OP_INVLHS);
64217 }
64218 DUK__SETTEMP(comp_ctx, reg_res + 1);
64219 duk__ivalue_regconst(res, (duk_regconst_t) reg_res);
64220 return;
64221 }
64222
64223 plain_value:
64224 {
64225 /* Stack top contains plain value */
64226 duk__ivalue_plain_fromstack(comp_ctx, res);
64227 return;
64228 }
64229
64230 syntax_error:
64231 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_EXPRESSION);
64232}
64233
64234/* XXX: add flag to indicate whether caller cares about return value; this
64235 * affects e.g. handling of assignment expressions. This change needs API
64236 * changes elsewhere too.
64237 */
64238DUK_LOCAL void duk__expr_led(duk_compiler_ctx *comp_ctx, duk_ivalue *left, duk_ivalue *res) {
64239 duk_hthread *thr = comp_ctx->thr;
64240 duk_context *ctx = (duk_context *) thr;
64241 duk_token *tk;
64242 duk_small_int_t tok;
64243 duk_uint32_t args; /* temp variable to pass constants and flags to shared code */
64244
64245 /*
64246 * ctx->prev_token token to process with duk__expr_led()
64247 * ctx->curr_token updated by caller
64248 */
64249
64250 comp_ctx->curr_func.led_count++;
64251
64252 /* The token in the switch has already been eaten here */
64253 tk = &comp_ctx->prev_token;
64254 tok = tk->t;
64255
64256 DUK_DDD(DUK_DDDPRINT("duk__expr_led(), prev_token.t=%ld, allow_in=%ld, paren_level=%ld",
64257 (long) tk->t, (long) comp_ctx->curr_func.allow_in, (long) comp_ctx->curr_func.paren_level));
64258
64259 /* XXX: default priority for infix operators is duk__expr_lbp(tok) -> get it here? */
64260
64261 switch (tok) {
64262
64263 /* PRIMARY EXPRESSIONS */
64264
64265 case DUK_TOK_PERIOD: {
64266 /* Property access expressions are critical for correct LHS ordering,
64267 * see comments in duk__expr()!
64268 *
64269 * A conservative approach would be to use duk__ivalue_totempconst()
64270 * for 'left'. However, allowing a reg-bound variable seems safe here
64271 * and is nice because "foo.bar" is a common expression. If the ivalue
64272 * is used in an expression a GETPROP will occur before any changes to
64273 * the base value can occur. If the ivalue is used as an assignment
64274 * LHS, the assignment code will ensure the base value is safe from
64275 * RHS mutation.
64276 */
64277
64278 /* XXX: This now coerces an identifier into a GETVAR to a temp, which
64279 * causes an extra LDREG in call setup. It's sufficient to coerce to a
64280 * unary ivalue?
64281 */
64282 duk__ivalue_toplain(comp_ctx, left);
64283
64284 /* NB: must accept reserved words as property name */
64285 if (comp_ctx->curr_token.t_nores != DUK_TOK_IDENTIFIER) {
64286 DUK_ERROR_SYNTAX(thr, DUK_STR_EXPECTED_IDENTIFIER);
64287 }
64288
64289 res->t = DUK_IVAL_PROP;
64290 duk__copy_ispec(comp_ctx, &left->x1, &res->x1); /* left.x1 -> res.x1 */
64291 DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
64292 duk_push_hstring(ctx, comp_ctx->curr_token.str1);
64293 duk_replace(ctx, res->x2.valstack_idx);
64294 res->x2.t = DUK_ISPEC_VALUE;
64295
64296 /* special RegExp literal handling after IdentifierName */
64297 comp_ctx->curr_func.reject_regexp_in_adv = 1;
64298
64299 duk__advance(comp_ctx);
64300 return;
64301 }
64302 case DUK_TOK_LBRACKET: {
64303 /* Property access expressions are critical for correct LHS ordering,
64304 * see comments in duk__expr()!
64305 */
64306
64307 /* XXX: optimize temp reg use */
64308 /* XXX: similar coercion issue as in DUK_TOK_PERIOD */
64309 /* XXX: coerce to regs? it might be better for enumeration use, where the
64310 * same PROP ivalue is used multiple times. Or perhaps coerce PROP further
64311 * there?
64312 */
64313 /* XXX: for simple cases like x['y'] an unnecessary LDREG is
64314 * emitted for the base value; could avoid it if we knew that
64315 * the key expression is safe (e.g. just a single literal).
64316 */
64317
64318 /* The 'left' value must not be a register bound variable
64319 * because it may be mutated during the rest of the expression
64320 * and E5.1 Section 11.2.1 specifies the order of evaluation
64321 * so that the base value is evaluated first.
64322 * See: test-bug-nested-prop-mutate.js.
64323 */
64324 duk__ivalue_totempconst(comp_ctx, left);
64325 duk__expr_toplain(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); /* Expression, ']' terminates */
64326 duk__advance_expect(comp_ctx, DUK_TOK_RBRACKET);
64327
64328 res->t = DUK_IVAL_PROP;
64329 duk__copy_ispec(comp_ctx, &res->x1, &res->x2); /* res.x1 -> res.x2 */
64330 duk__copy_ispec(comp_ctx, &left->x1, &res->x1); /* left.x1 -> res.x1 */
64331 return;
64332 }
64333 case DUK_TOK_LPAREN: {
64334 /* function call */
64335 duk_reg_t reg_cs = DUK__ALLOCTEMPS(comp_ctx, 2);
64336 duk_int_t nargs;
64337 duk_small_uint_t call_op = DUK_OP_CALL;
64338
64339 /* XXX: attempt to get the call result to "next temp" whenever
64340 * possible to avoid unnecessary register shuffles.
64341 */
64342
64343 /*
64344 * Setup call: target and 'this' binding. Three cases:
64345 *
64346 * 1. Identifier base (e.g. "foo()")
64347 * 2. Property base (e.g. "foo.bar()")
64348 * 3. Register base (e.g. "foo()()"; i.e. when a return value is a function)
64349 */
64350
64351 if (left->t == DUK_IVAL_VAR) {
64352 duk_hstring *h_varname;
64353 duk_reg_t reg_varbind;
64354 duk_regconst_t rc_varname;
64355
64356 DUK_DDD(DUK_DDDPRINT("function call with identifier base"));
64357
64358 h_varname = duk_known_hstring(ctx, left->x1.valstack_idx);
64359 if (h_varname == DUK_HTHREAD_STRING_EVAL(thr)) {
64360 /* Potential direct eval call detected, flag the CALL
64361 * so that a run-time "direct eval" check is made and
64362 * special behavior may be triggered. Note that this
64363 * does not prevent 'eval' from being register bound.
64364 */
64365 DUK_DDD(DUK_DDDPRINT("function call with identifier 'eval' "
64366 "-> using EVALCALL, marking function "
64367 "as may_direct_eval"));
64368 call_op = DUK_OP_EVALCALL;
64369 comp_ctx->curr_func.may_direct_eval = 1;
64370 }
64371
64372 duk_dup(ctx, left->x1.valstack_idx);
64373 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
64374 duk__emit_a_bc(comp_ctx,
64375 DUK_OP_CSREG | DUK__EMIT_FLAG_A_IS_SOURCE,
64376 (duk_regconst_t) reg_varbind,
64377 (duk_regconst_t) (reg_cs + 0));
64378 } else {
64379 /* XXX: expand target register or constant field to
64380 * reduce shuffling.
64381 */
64382 DUK_ASSERT(DUK__ISCONST(rc_varname));
64383 duk__emit_a_b(comp_ctx,
64384 DUK_OP_CSVAR | DUK__EMIT_FLAG_BC_REGCONST,
64385 (duk_regconst_t) (reg_cs + 0),
64386 rc_varname);
64387 }
64388 } else if (left->t == DUK_IVAL_PROP) {
64389 /* Call through a property lookup, E5 Section 11.2.3, step 6.a.i,
64390 * E5 Section 10.4.3. There used to be a separate CSPROP opcode
64391 * but a typical call setup took 3 opcodes (e.g. LDREG, LDCONST,
64392 * CSPROP) and the same can be achieved with ordinary loads.
64393 */
64394 DUK_DDD(DUK_DDDPRINT("function call with property base"));
64395
64396 duk__ispec_toforcedreg(comp_ctx, &left->x1, reg_cs + 1); /* base */
64397 duk__ivalue_toforcedreg(comp_ctx, left, reg_cs + 0); /* base[key] */
64398 } else {
64399 DUK_DDD(DUK_DDDPRINT("function call with register base"));
64400
64401 duk__ivalue_toforcedreg(comp_ctx, left, reg_cs + 0);
64402 duk__emit_a_bc(comp_ctx,
64403 DUK_OP_CSREG | DUK__EMIT_FLAG_A_IS_SOURCE,
64404 (duk_regconst_t) (reg_cs + 0),
64405 (duk_regconst_t) (reg_cs + 0)); /* in-place setup */
64406 }
64407
64408 DUK__SETTEMP(comp_ctx, reg_cs + 2);
64409 nargs = duk__parse_arguments(comp_ctx, res); /* parse args starting from "next temp" */
64410
64411 /* Tailcalls are handled by back-patching the opcode to TAILCALL to the
64412 * already emitted instruction later (in return statement parser).
64413 */
64414
64415 duk__emit_a_bc(comp_ctx,
64416 call_op | DUK__EMIT_FLAG_NO_SHUFFLE_A,
64417 (duk_regconst_t) nargs /*numargs*/,
64418 (duk_regconst_t) reg_cs /*basereg*/);
64419 DUK__SETTEMP(comp_ctx, reg_cs + 1); /* result in csreg */
64420
64421 duk__ivalue_regconst(res, (duk_regconst_t) reg_cs);
64422 return;
64423 }
64424
64425 /* POSTFIX EXPRESSION */
64426
64427 case DUK_TOK_INCREMENT: {
64428 args = (DUK_OP_POSTINCP_RR << 16) + (DUK_OP_POSTINCR << 8) + 0;
64429 goto postincdec;
64430 }
64431 case DUK_TOK_DECREMENT: {
64432 args = (DUK_OP_POSTDECP_RR << 16) + (DUK_OP_POSTDECR << 8) + 0;
64433 goto postincdec;
64434 }
64435
64436 /* EXPONENTIATION EXPRESSION */
64437
64438#if defined(DUK_USE_ES7_EXP_OPERATOR)
64439 case DUK_TOK_EXP: {
64440 args = (DUK_OP_EXP << 8) + DUK__BP_EXPONENTIATION - 1; /* UnaryExpression */
64441 goto binary;
64442 }
64443#endif
64444
64445 /* MULTIPLICATIVE EXPRESSION */
64446
64447 case DUK_TOK_MUL: {
64448 args = (DUK_OP_MUL << 8) + DUK__BP_MULTIPLICATIVE; /* ExponentiationExpression */
64449 goto binary;
64450 }
64451 case DUK_TOK_DIV: {
64452 args = (DUK_OP_DIV << 8) + DUK__BP_MULTIPLICATIVE; /* ExponentiationExpression */
64453 goto binary;
64454 }
64455 case DUK_TOK_MOD: {
64456 args = (DUK_OP_MOD << 8) + DUK__BP_MULTIPLICATIVE; /* ExponentiationExpression */
64457 goto binary;
64458 }
64459
64460 /* ADDITIVE EXPRESSION */
64461
64462 case DUK_TOK_ADD: {
64463 args = (DUK_OP_ADD << 8) + DUK__BP_ADDITIVE; /* MultiplicativeExpression */
64464 goto binary;
64465 }
64466 case DUK_TOK_SUB: {
64467 args = (DUK_OP_SUB << 8) + DUK__BP_ADDITIVE; /* MultiplicativeExpression */
64468 goto binary;
64469 }
64470
64471 /* SHIFT EXPRESSION */
64472
64473 case DUK_TOK_ALSHIFT: {
64474 /* << */
64475 args = (DUK_OP_BASL << 8) + DUK__BP_SHIFT;
64476 goto binary;
64477 }
64478 case DUK_TOK_ARSHIFT: {
64479 /* >> */
64480 args = (DUK_OP_BASR << 8) + DUK__BP_SHIFT;
64481 goto binary;
64482 }
64483 case DUK_TOK_RSHIFT: {
64484 /* >>> */
64485 args = (DUK_OP_BLSR << 8) + DUK__BP_SHIFT;
64486 goto binary;
64487 }
64488
64489 /* RELATIONAL EXPRESSION */
64490
64491 case DUK_TOK_LT: {
64492 /* < */
64493 args = (DUK_OP_LT << 8) + DUK__BP_RELATIONAL;
64494 goto binary;
64495 }
64496 case DUK_TOK_GT: {
64497 args = (DUK_OP_GT << 8) + DUK__BP_RELATIONAL;
64498 goto binary;
64499 }
64500 case DUK_TOK_LE: {
64501 args = (DUK_OP_LE << 8) + DUK__BP_RELATIONAL;
64502 goto binary;
64503 }
64504 case DUK_TOK_GE: {
64505 args = (DUK_OP_GE << 8) + DUK__BP_RELATIONAL;
64506 goto binary;
64507 }
64508 case DUK_TOK_INSTANCEOF: {
64509 args = (DUK_OP_INSTOF << 8) + DUK__BP_RELATIONAL;
64510 goto binary;
64511 }
64512 case DUK_TOK_IN: {
64513 args = (DUK_OP_IN << 8) + DUK__BP_RELATIONAL;
64514 goto binary;
64515 }
64516
64517 /* EQUALITY EXPRESSION */
64518
64519 case DUK_TOK_EQ: {
64520 args = (DUK_OP_EQ << 8) + DUK__BP_EQUALITY;
64521 goto binary;
64522 }
64523 case DUK_TOK_NEQ: {
64524 args = (DUK_OP_NEQ << 8) + DUK__BP_EQUALITY;
64525 goto binary;
64526 }
64527 case DUK_TOK_SEQ: {
64528 args = (DUK_OP_SEQ << 8) + DUK__BP_EQUALITY;
64529 goto binary;
64530 }
64531 case DUK_TOK_SNEQ: {
64532 args = (DUK_OP_SNEQ << 8) + DUK__BP_EQUALITY;
64533 goto binary;
64534 }
64535
64536 /* BITWISE EXPRESSIONS */
64537
64538 case DUK_TOK_BAND: {
64539 args = (DUK_OP_BAND << 8) + DUK__BP_BAND;
64540 goto binary;
64541 }
64542 case DUK_TOK_BXOR: {
64543 args = (DUK_OP_BXOR << 8) + DUK__BP_BXOR;
64544 goto binary;
64545 }
64546 case DUK_TOK_BOR: {
64547 args = (DUK_OP_BOR << 8) + DUK__BP_BOR;
64548 goto binary;
64549 }
64550
64551 /* LOGICAL EXPRESSIONS */
64552
64553 case DUK_TOK_LAND: {
64554 /* syntactically left-associative but parsed as right-associative */
64555 args = (1 << 8) + DUK__BP_LAND - 1;
64556 goto binary_logical;
64557 }
64558 case DUK_TOK_LOR: {
64559 /* syntactically left-associative but parsed as right-associative */
64560 args = (0 << 8) + DUK__BP_LOR - 1;
64561 goto binary_logical;
64562 }
64563
64564 /* CONDITIONAL EXPRESSION */
64565
64566 case DUK_TOK_QUESTION: {
64567 /* XXX: common reg allocation need is to reuse a sub-expression's temp reg,
64568 * but only if it really is a temp. Nothing fancy here now.
64569 */
64570 duk_reg_t reg_temp;
64571 duk_int_t pc_jump1;
64572 duk_int_t pc_jump2;
64573
64574 reg_temp = DUK__ALLOCTEMP(comp_ctx);
64575 duk__ivalue_toforcedreg(comp_ctx, left, reg_temp);
64576 duk__emit_if_true_skip(comp_ctx, reg_temp);
64577 pc_jump1 = duk__emit_jump_empty(comp_ctx); /* jump to false */
64578 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/); /* AssignmentExpression */
64579 duk__advance_expect(comp_ctx, DUK_TOK_COLON);
64580 pc_jump2 = duk__emit_jump_empty(comp_ctx); /* jump to end */
64581 duk__patch_jump_here(comp_ctx, pc_jump1);
64582 duk__expr_toforcedreg(comp_ctx, res, DUK__BP_COMMA /*rbp_flags*/, reg_temp /*forced_reg*/); /* AssignmentExpression */
64583 duk__patch_jump_here(comp_ctx, pc_jump2);
64584
64585 DUK__SETTEMP(comp_ctx, reg_temp + 1);
64586 duk__ivalue_regconst(res, (duk_regconst_t) reg_temp);
64587 return;
64588 }
64589
64590 /* ASSIGNMENT EXPRESSION */
64591
64592 case DUK_TOK_EQUALSIGN: {
64593 /*
64594 * Assignments are right associative, allows e.g.
64595 * a = 5;
64596 * a += b = 9; // same as a += (b = 9)
64597 * -> expression value 14, a = 14, b = 9
64598 *
64599 * Right associativiness is reflected in the BP for recursion,
64600 * "-1" ensures assignment operations are allowed.
64601 *
64602 * XXX: just use DUK__BP_COMMA (i.e. no need for 2-step bp levels)?
64603 */
64604 args = (DUK_OP_NONE << 8) + DUK__BP_ASSIGNMENT - 1; /* DUK_OP_NONE marks a 'plain' assignment */
64605 goto assign;
64606 }
64607 case DUK_TOK_ADD_EQ: {
64608 /* right associative */
64609 args = (DUK_OP_ADD << 8) + DUK__BP_ASSIGNMENT - 1;
64610 goto assign;
64611 }
64612 case DUK_TOK_SUB_EQ: {
64613 /* right associative */
64614 args = (DUK_OP_SUB << 8) + DUK__BP_ASSIGNMENT - 1;
64615 goto assign;
64616 }
64617 case DUK_TOK_MUL_EQ: {
64618 /* right associative */
64619 args = (DUK_OP_MUL << 8) + DUK__BP_ASSIGNMENT - 1;
64620 goto assign;
64621 }
64622 case DUK_TOK_DIV_EQ: {
64623 /* right associative */
64624 args = (DUK_OP_DIV << 8) + DUK__BP_ASSIGNMENT - 1;
64625 goto assign;
64626 }
64627 case DUK_TOK_MOD_EQ: {
64628 /* right associative */
64629 args = (DUK_OP_MOD << 8) + DUK__BP_ASSIGNMENT - 1;
64630 goto assign;
64631 }
64632#if defined(DUK_USE_ES7_EXP_OPERATOR)
64633 case DUK_TOK_EXP_EQ: {
64634 /* right associative */
64635 args = (DUK_OP_EXP << 8) + DUK__BP_ASSIGNMENT - 1;
64636 goto assign;
64637 }
64638#endif
64639 case DUK_TOK_ALSHIFT_EQ: {
64640 /* right associative */
64641 args = (DUK_OP_BASL << 8) + DUK__BP_ASSIGNMENT - 1;
64642 goto assign;
64643 }
64644 case DUK_TOK_ARSHIFT_EQ: {
64645 /* right associative */
64646 args = (DUK_OP_BASR << 8) + DUK__BP_ASSIGNMENT - 1;
64647 goto assign;
64648 }
64649 case DUK_TOK_RSHIFT_EQ: {
64650 /* right associative */
64651 args = (DUK_OP_BLSR << 8) + DUK__BP_ASSIGNMENT - 1;
64652 goto assign;
64653 }
64654 case DUK_TOK_BAND_EQ: {
64655 /* right associative */
64656 args = (DUK_OP_BAND << 8) + DUK__BP_ASSIGNMENT - 1;
64657 goto assign;
64658 }
64659 case DUK_TOK_BOR_EQ: {
64660 /* right associative */
64661 args = (DUK_OP_BOR << 8) + DUK__BP_ASSIGNMENT - 1;
64662 goto assign;
64663 }
64664 case DUK_TOK_BXOR_EQ: {
64665 /* right associative */
64666 args = (DUK_OP_BXOR << 8) + DUK__BP_ASSIGNMENT - 1;
64667 goto assign;
64668 }
64669
64670 /* COMMA */
64671
64672 case DUK_TOK_COMMA: {
64673 /* right associative */
64674
64675 duk__ivalue_toplain_ignore(comp_ctx, left); /* need side effects, not value */
64676 duk__expr_toplain(comp_ctx, res, DUK__BP_COMMA - 1 /*rbp_flags*/);
64677
64678 /* return 'res' (of right part) as our result */
64679 return;
64680 }
64681
64682 default: {
64683 break;
64684 }
64685 }
64686
64687 DUK_D(DUK_DPRINT("parse error: unexpected token: %ld", (long) tok));
64688 DUK_ERROR_SYNTAX(thr, DUK_STR_PARSE_ERROR);
64689 return;
64690
64691#if 0
64692 /* XXX: shared handling for 'duk__expr_lhs'? */
64693 if (comp_ctx->curr_func.paren_level == 0 && XXX) {
64694 comp_ctx->curr_func.duk__expr_lhs = 0;
64695 }
64696#endif
64697
64698 binary:
64699 /*
64700 * Shared handling of binary operations
64701 *
64702 * args = (opcode << 8) + rbp
64703 */
64704 {
64705 duk__ivalue_toplain(comp_ctx, left);
64706 duk__expr_toplain(comp_ctx, res, args & 0xff /*rbp_flags*/);
64707
64708 /* combine left->x1 and res->x1 (right->x1, really) -> (left->x1 OP res->x1) */
64709 DUK_ASSERT(left->t == DUK_IVAL_PLAIN);
64710 DUK_ASSERT(res->t == DUK_IVAL_PLAIN);
64711
64712 res->t = DUK_IVAL_ARITH;
64713 res->op = (args >> 8) & 0xff;
64714
64715 res->x2.t = res->x1.t;
64716 res->x2.regconst = res->x1.regconst;
64717 duk_copy(ctx, res->x1.valstack_idx, res->x2.valstack_idx);
64718
64719 res->x1.t = left->x1.t;
64720 res->x1.regconst = left->x1.regconst;
64721 duk_copy(ctx, left->x1.valstack_idx, res->x1.valstack_idx);
64722
64723 DUK_DDD(DUK_DDDPRINT("binary op, res: t=%ld, x1.t=%ld, x1.regconst=0x%08lx, x2.t=%ld, x2.regconst=0x%08lx",
64724 (long) res->t, (long) res->x1.t, (unsigned long) res->x1.regconst, (long) res->x2.t, (unsigned long) res->x2.regconst));
64725 return;
64726 }
64727
64728 binary_logical:
64729 /*
64730 * Shared handling for logical AND and logical OR.
64731 *
64732 * args = (truthval << 8) + rbp
64733 *
64734 * Truthval determines when to skip right-hand-side.
64735 * For logical AND truthval=1, for logical OR truthval=0.
64736 *
64737 * See doc/compiler.rst for discussion on compiling logical
64738 * AND and OR expressions. The approach here is very simplistic,
64739 * generating extra jumps and multiple evaluations of truth values,
64740 * but generates code on-the-fly with only local back-patching.
64741 *
64742 * Both logical AND and OR are syntactically left-associated.
64743 * However, logical ANDs are compiled as right associative
64744 * expressions, i.e. "A && B && C" as "A && (B && C)", to allow
64745 * skip jumps to skip over the entire tail. Similarly for logical OR.
64746 */
64747
64748 {
64749 duk_reg_t reg_temp;
64750 duk_int_t pc_jump;
64751 duk_small_uint_t args_truthval = args >> 8;
64752 duk_small_uint_t args_rbp = args & 0xff;
64753
64754 /* XXX: unoptimal use of temps, resetting */
64755
64756 reg_temp = DUK__ALLOCTEMP(comp_ctx);
64757
64758 duk__ivalue_toforcedreg(comp_ctx, left, reg_temp);
64759 DUK_ASSERT(DUK__ISREG(reg_temp));
64760 duk__emit_bc(comp_ctx,
64761 (args_truthval ? DUK_OP_IFTRUE_R : DUK_OP_IFFALSE_R),
64762 (duk_regconst_t) reg_temp); /* skip jump conditionally */
64763 pc_jump = duk__emit_jump_empty(comp_ctx);
64764 duk__expr_toforcedreg(comp_ctx, res, args_rbp /*rbp_flags*/, reg_temp /*forced_reg*/);
64765 duk__patch_jump_here(comp_ctx, pc_jump);
64766
64767 duk__ivalue_regconst(res, (duk_regconst_t) reg_temp);
64768 return;
64769 }
64770
64771 assign:
64772 /*
64773 * Shared assignment expression handling
64774 *
64775 * args = (opcode << 8) + rbp
64776 *
64777 * If 'opcode' is DUK_OP_NONE, plain assignment without arithmetic.
64778 * Syntactically valid left-hand-side forms which are not accepted as
64779 * left-hand-side values (e.g. as in "f() = 1") must NOT cause a
64780 * SyntaxError, but rather a run-time ReferenceError.
64781 *
64782 * When evaluating X <op>= Y, the LHS (X) is conceptually evaluated
64783 * to a temporary first. The RHS is then evaluated. Finally, the
64784 * <op> is applied to the initial value of RHS (not the value after
64785 * RHS evaluation), and written to X. Doing so concretely generates
64786 * inefficient code so we'd like to avoid the temporary when possible.
64787 * See: https://github.com/svaarala/duktape/pull/992.
64788 *
64789 * The expression value (final LHS value, written to RHS) is
64790 * conceptually copied into a fresh temporary so that it won't
64791 * change even if the LHS/RHS values change in outer expressions.
64792 * For example, it'd be generally incorrect for the expression value
64793 * to be the RHS register binding, unless there's a guarantee that it
64794 * won't change during further expression evaluation. Using the
64795 * temporary concretely produces inefficient bytecode, so we try to
64796 * avoid the extra temporary for some known-to-be-safe cases.
64797 * Currently the only safe case we detect is a "top level assignment",
64798 * for example "x = y + z;", where the assignment expression value is
64799 * ignored.
64800 * See: test-dev-assign-expr.js and test-bug-assign-mutate-gh381.js.
64801 */
64802
64803 {
64804 duk_small_uint_t args_op = args >> 8;
64805 duk_small_uint_t args_rbp = args & 0xff;
64806 duk_bool_t toplevel_assign;
64807
64808 /* XXX: here we need to know if 'left' is left-hand-side compatible.
64809 * That information is no longer available from current expr parsing
64810 * state; it would need to be carried into the 'left' ivalue or by
64811 * some other means.
64812 */
64813
64814 /* A top-level assignment is e.g. "x = y;". For these it's safe
64815 * to use the RHS as-is as the expression value, even if the RHS
64816 * is a reg-bound identifier. The RHS ('res') is right associative
64817 * so it has consumed all other assignment level operations; the
64818 * only relevant lower binding power construct is comma operator
64819 * which will ignore the expression value provided here. Usually
64820 * the top level assignment expression value is ignored, but it
64821 * is relevant for e.g. eval code.
64822 */
64823 toplevel_assign = (comp_ctx->curr_func.nud_count == 1 && /* one token before */
64824 comp_ctx->curr_func.led_count == 1); /* one operator (= assign) */
64825 DUK_DDD(DUK_DDDPRINT("assignment: nud_count=%ld, led_count=%ld, toplevel_assign=%ld",
64826 (long) comp_ctx->curr_func.nud_count,
64827 (long) comp_ctx->curr_func.led_count,
64828 (long) toplevel_assign));
64829
64830 if (left->t == DUK_IVAL_VAR) {
64831 duk_hstring *h_varname;
64832 duk_reg_t reg_varbind;
64833 duk_regconst_t rc_varname;
64834
64835 DUK_ASSERT(left->x1.t == DUK_ISPEC_VALUE); /* LHS is already side effect free */
64836
64837 h_varname = duk_known_hstring(ctx, left->x1.valstack_idx);
64838 if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
64839 /* E5 Section 11.13.1 (and others for other assignments), step 4. */
64840 goto syntax_error_lvalue;
64841 }
64842 duk_dup(ctx, left->x1.valstack_idx);
64843 (void) duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname);
64844
64845 if (args_op == DUK_OP_NONE) {
64846 duk__expr(comp_ctx, res, args_rbp /*rbp_flags*/);
64847 if (toplevel_assign) {
64848 /* Any 'res' will do. */
64849 DUK_DDD(DUK_DDDPRINT("plain assignment, toplevel assign, use as is"));
64850 } else {
64851 /* 'res' must be a plain ivalue, and not register-bound variable. */
64852 DUK_DDD(DUK_DDDPRINT("plain assignment, not toplevel assign, ensure not a reg-bound identifier"));
64853 if (res->t != DUK_IVAL_PLAIN || (res->x1.t == DUK_ISPEC_REGCONST &&
64854 (res->x1.regconst & DUK__CONST_MARKER) == 0 &&
64855 !DUK__ISTEMP(comp_ctx, res->x1.regconst))) {
64856 duk__ivalue_totempconst(comp_ctx, res);
64857 }
64858 }
64859 } else {
64860 /* For X <op>= Y we need to evaluate the pre-op
64861 * value of X before evaluating the RHS: the RHS
64862 * can change X, but when we do <op> we must use
64863 * the pre-op value.
64864 */
64865 duk_reg_t reg_temp;
64866
64867 reg_temp = DUK__ALLOCTEMP(comp_ctx);
64868
64869 if (reg_varbind >= 0) {
64870 duk_reg_t reg_res;
64871 duk_reg_t reg_src;
64872 duk_int_t pc_temp_load;
64873 duk_int_t pc_before_rhs;
64874 duk_int_t pc_after_rhs;
64875
64876 if (toplevel_assign) {
64877 /* 'reg_varbind' is the operation result and can also
64878 * become the expression value for top level assignments
64879 * such as: "var x; x += y;".
64880 */
64881 DUK_DD(DUK_DDPRINT("<op>= expression is top level, write directly to reg_varbind"));
64882 reg_res = reg_varbind;
64883 } else {
64884 /* Not safe to use 'reg_varbind' as assignment expression
64885 * value, so go through a temp.
64886 */
64887 DUK_DD(DUK_DDPRINT("<op>= expression is not top level, write to reg_temp"));
64888 reg_res = reg_temp; /* reg_res should be smallest possible */
64889 reg_temp = DUK__ALLOCTEMP(comp_ctx);
64890 }
64891
64892 /* Try to optimize X <op>= Y for reg-bound
64893 * variables. Detect side-effect free RHS
64894 * narrowly by seeing whether it emits code.
64895 * If not, rewind the code emitter and overwrite
64896 * the unnecessary temp reg load.
64897 */
64898
64899 pc_temp_load = duk__get_current_pc(comp_ctx);
64900 duk__emit_a_bc(comp_ctx,
64901 DUK_OP_LDREG,
64902 (duk_regconst_t) reg_temp,
64903 reg_varbind);
64904
64905 pc_before_rhs = duk__get_current_pc(comp_ctx);
64906 duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
64907 DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
64908 pc_after_rhs = duk__get_current_pc(comp_ctx);
64909
64910 DUK_DD(DUK_DDPRINT("pc_temp_load=%ld, pc_before_rhs=%ld, pc_after_rhs=%ld",
64911 (long) pc_temp_load, (long) pc_before_rhs,
64912 (long) pc_after_rhs));
64913
64914 if (pc_after_rhs == pc_before_rhs) {
64915 /* Note: if the reg_temp load generated shuffling
64916 * instructions, we may need to rewind more than
64917 * one instruction, so use explicit PC computation.
64918 */
64919 DUK_DD(DUK_DDPRINT("rhs is side effect free, rewind and avoid unnecessary temp for reg-based <op>="));
64920 DUK_BW_ADD_PTR(comp_ctx->thr, &comp_ctx->curr_func.bw_code, (pc_temp_load - pc_before_rhs) * sizeof(duk_compiler_instr));
64921 reg_src = reg_varbind;
64922 } else {
64923 DUK_DD(DUK_DDPRINT("rhs evaluation emitted code, not sure if rhs is side effect free; use temp reg for LHS"));
64924 reg_src = reg_temp;
64925 }
64926
64927 duk__emit_a_b_c(comp_ctx,
64928 args_op | DUK__EMIT_FLAG_BC_REGCONST,
64929 (duk_regconst_t) reg_res,
64930 (duk_regconst_t) reg_src,
64931 res->x1.regconst);
64932
64933 res->x1.regconst = (duk_regconst_t) reg_res;
64934
64935 /* Ensure compact use of temps. */
64936 if (DUK__ISTEMP(comp_ctx, reg_res)) {
64937 DUK__SETTEMP(comp_ctx, reg_res + 1);
64938 }
64939 } else {
64940 /* When LHS is not register bound, always go through a
64941 * temporary. No optimization for top level assignment.
64942 */
64943
64944 duk__emit_a_bc(comp_ctx,
64945 DUK_OP_GETVAR,
64946 (duk_regconst_t) reg_temp,
64947 rc_varname);
64948
64949 duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
64950 DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
64951
64952 duk__emit_a_b_c(comp_ctx,
64953 args_op | DUK__EMIT_FLAG_BC_REGCONST,
64954 (duk_regconst_t) reg_temp,
64955 (duk_regconst_t) reg_temp,
64956 res->x1.regconst);
64957 res->x1.regconst = (duk_regconst_t) reg_temp;
64958 }
64959
64960 DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
64961 }
64962
64963 /* At this point 'res' holds the potential expression value.
64964 * It can be basically any ivalue here, including a reg-bound
64965 * identifier (if code above deems it safe) or a unary/binary
64966 * operation. Operations must be resolved to a side effect free
64967 * plain value, and the side effects must happen exactly once.
64968 */
64969
64970 if (reg_varbind >= 0) {
64971 if (res->t != DUK_IVAL_PLAIN) {
64972 /* Resolve 'res' directly into the LHS binding, and use
64973 * that as the expression value if safe. If not safe,
64974 * resolve to a temp/const and copy to LHS.
64975 */
64976 if (toplevel_assign) {
64977 duk__ivalue_toforcedreg(comp_ctx, res, (duk_int_t) reg_varbind);
64978 } else {
64979 duk__ivalue_totempconst(comp_ctx, res);
64980 duk__copy_ivalue(comp_ctx, res, left); /* use 'left' as a temp */
64981 duk__ivalue_toforcedreg(comp_ctx, left, (duk_int_t) reg_varbind);
64982 }
64983 } else {
64984 /* Use 'res' as the expression value (it's side effect
64985 * free and may be a plain value, a register, or a
64986 * constant) and write it to the LHS binding too.
64987 */
64988 duk__copy_ivalue(comp_ctx, res, left); /* use 'left' as a temp */
64989 duk__ivalue_toforcedreg(comp_ctx, left, (duk_int_t) reg_varbind);
64990 }
64991 } else {
64992 /* Only a reg fits into 'A' so coerce 'res' into a register
64993 * for PUTVAR.
64994 *
64995 * XXX: here the current A/B/C split is suboptimal: we could
64996 * just use 9 bits for reg_res (and support constants) and 17
64997 * instead of 18 bits for the varname const index.
64998 */
64999
65000 duk__ivalue_toreg(comp_ctx, res);
65001 duk__emit_a_bc(comp_ctx,
65002 DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
65003 res->x1.regconst,
65004 rc_varname);
65005 }
65006
65007 /* 'res' contains expression value */
65008 } else if (left->t == DUK_IVAL_PROP) {
65009 /* E5 Section 11.13.1 (and others) step 4 never matches for prop writes -> no check */
65010 duk_reg_t reg_obj;
65011 duk_regconst_t rc_key;
65012 duk_regconst_t rc_res;
65013 duk_reg_t reg_temp;
65014
65015 /* Property access expressions ('a[b]') are critical to correct
65016 * LHS evaluation ordering, see test-dev-assign-eval-order*.js.
65017 * We must make sure that the LHS target slot (base object and
65018 * key) don't change during RHS evaluation. The only concrete
65019 * problem is a register reference to a variable-bound register
65020 * (i.e., non-temp). Require temp regs for both key and base.
65021 *
65022 * Don't allow a constant for the object (even for a number
65023 * etc), as it goes into the 'A' field of the opcode.
65024 */
65025
65026 reg_obj = duk__ispec_toregconst_raw(comp_ctx,
65027 &left->x1,
65028 -1 /*forced_reg*/,
65029 DUK__IVAL_FLAG_REQUIRE_TEMP /*flags*/);
65030
65031 rc_key = duk__ispec_toregconst_raw(comp_ctx,
65032 &left->x2,
65033 -1 /*forced_reg*/,
65034 DUK__IVAL_FLAG_REQUIRE_TEMP | DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
65035
65036 /* Evaluate RHS only when LHS is safe. */
65037
65038 if (args_op == DUK_OP_NONE) {
65039 duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
65040 DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
65041 rc_res = res->x1.regconst;
65042 } else {
65043 reg_temp = DUK__ALLOCTEMP(comp_ctx);
65044 duk__emit_a_b_c(comp_ctx,
65045 DUK_OP_GETPROP | DUK__EMIT_FLAG_BC_REGCONST,
65046 (duk_regconst_t) reg_temp,
65047 (duk_regconst_t) reg_obj,
65048 rc_key);
65049
65050 duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
65051 DUK_ASSERT(res->t == DUK_IVAL_PLAIN && res->x1.t == DUK_ISPEC_REGCONST);
65052
65053 duk__emit_a_b_c(comp_ctx,
65054 args_op | DUK__EMIT_FLAG_BC_REGCONST,
65055 (duk_regconst_t) reg_temp,
65056 (duk_regconst_t) reg_temp,
65057 res->x1.regconst);
65058 rc_res = (duk_regconst_t) reg_temp;
65059 }
65060
65061 duk__emit_a_b_c(comp_ctx,
65062 DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE | DUK__EMIT_FLAG_BC_REGCONST,
65063 (duk_regconst_t) reg_obj,
65064 rc_key,
65065 rc_res);
65066
65067 duk__ivalue_regconst(res, (duk_regconst_t) rc_res);
65068 } else {
65069 /* No support for lvalues returned from new or function call expressions.
65070 * However, these must NOT cause compile-time SyntaxErrors, but run-time
65071 * ReferenceErrors. Both left and right sides of the assignment must be
65072 * evaluated before throwing a ReferenceError. For instance:
65073 *
65074 * f() = g();
65075 *
65076 * must result in f() being evaluated, then g() being evaluated, and
65077 * finally, a ReferenceError being thrown. See E5 Section 11.13.1.
65078 */
65079
65080 duk_regconst_t rc_res;
65081
65082 /* First evaluate LHS fully to ensure all side effects are out. */
65083 duk__ivalue_toplain_ignore(comp_ctx, left);
65084
65085 /* Then evaluate RHS fully (its value becomes the expression value too).
65086 * Technically we'd need the side effect safety check here too, but because
65087 * we always throw using INVLHS the result doesn't matter.
65088 */
65089 rc_res = duk__expr_toregconst(comp_ctx, res, args_rbp /*rbp_flags*/);
65090
65091 duk__emit_op_only(comp_ctx, DUK_OP_INVLHS);
65092
65093 duk__ivalue_regconst(res, (duk_regconst_t) rc_res);
65094 }
65095
65096 return;
65097 }
65098
65099 postincdec:
65100 {
65101 /*
65102 * Post-increment/decrement will return the original value as its
65103 * result value. However, even that value will be coerced using
65104 * ToNumber() which is quite awkward. Specific bytecode opcodes
65105 * are used to handle these semantics.
65106 *
65107 * Note that post increment/decrement has a "no LineTerminator here"
65108 * restriction. This is handled by duk__expr_lbp(), which forcibly terminates
65109 * the previous expression if a LineTerminator occurs before '++'/'--'.
65110 */
65111
65112 duk_reg_t reg_res;
65113 duk_small_uint_t args_op1 = (args >> 8) & 0xff; /* DUK_OP_POSTINCR/DUK_OP_POSTDECR */
65114 duk_small_uint_t args_op2 = args >> 16; /* DUK_OP_POSTINCP_RR/DUK_OP_POSTDECP_RR */
65115
65116 /* Specific assumptions for opcode numbering. */
65117 DUK_ASSERT(DUK_OP_POSTINCR + 4 == DUK_OP_POSTINCV);
65118 DUK_ASSERT(DUK_OP_POSTDECR + 4 == DUK_OP_POSTDECV);
65119
65120 reg_res = DUK__ALLOCTEMP(comp_ctx);
65121
65122 if (left->t == DUK_IVAL_VAR) {
65123 duk_hstring *h_varname;
65124 duk_reg_t reg_varbind;
65125 duk_regconst_t rc_varname;
65126
65127 h_varname = duk_known_hstring(ctx, left->x1.valstack_idx);
65128
65129 if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
65130 goto syntax_error;
65131 }
65132
65133 duk_dup(ctx, left->x1.valstack_idx);
65134 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
65135 duk__emit_a_bc(comp_ctx,
65136 args_op1, /* e.g. DUK_OP_POSTINCR */
65137 (duk_regconst_t) reg_res,
65138 (duk_regconst_t) reg_varbind);
65139 } else {
65140 duk__emit_a_bc(comp_ctx,
65141 args_op1 + 4, /* e.g. DUK_OP_POSTINCV */
65142 (duk_regconst_t) reg_res,
65143 rc_varname);
65144 }
65145
65146 DUK_DDD(DUK_DDDPRINT("postincdec to '%!O' -> reg_varbind=%ld, rc_varname=%ld",
65147 (duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname));
65148 } else if (left->t == DUK_IVAL_PROP) {
65149 duk_reg_t reg_obj; /* allocate to reg only (not const) */
65150 duk_regconst_t rc_key;
65151
65152 reg_obj = duk__ispec_toregconst_raw(comp_ctx, &left->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
65153 rc_key = duk__ispec_toregconst_raw(comp_ctx, &left->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
65154 duk__emit_a_b_c(comp_ctx,
65155 args_op2 | DUK__EMIT_FLAG_BC_REGCONST, /* e.g. DUK_OP_POSTINCP */
65156 (duk_regconst_t) reg_res,
65157 (duk_regconst_t) reg_obj,
65158 rc_key);
65159 } else {
65160 /* Technically return value is not needed because INVLHS will
65161 * unconditially throw a ReferenceError. Coercion is necessary
65162 * for proper semantics (consider ToNumber() called for an object).
65163 * Use DUK_OP_UNP with a dummy register to get ToNumber().
65164 */
65165 duk__ivalue_toforcedreg(comp_ctx, left, reg_res);
65166 duk__emit_bc(comp_ctx,
65167 DUK_OP_UNP,
65168 reg_res); /* for side effects, result ignored */
65169 duk__emit_op_only(comp_ctx,
65170 DUK_OP_INVLHS);
65171 }
65172
65173 DUK__SETTEMP(comp_ctx, reg_res + 1);
65174 duk__ivalue_regconst(res, (duk_regconst_t) reg_res);
65175 return;
65176 }
65177
65178 syntax_error:
65179 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_EXPRESSION);
65180 return;
65181
65182 syntax_error_lvalue:
65183 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_LVALUE);
65184 return;
65185}
65186
65187DUK_LOCAL duk_small_uint_t duk__expr_lbp(duk_compiler_ctx *comp_ctx) {
65188 duk_small_int_t tok = comp_ctx->curr_token.t;
65189
65190 DUK_ASSERT(tok >= DUK_TOK_MINVAL && tok <= DUK_TOK_MAXVAL);
65191 DUK_ASSERT(sizeof(duk__token_lbp) == DUK_TOK_MAXVAL + 1);
65192
65193 /* XXX: integrate support for this into led() instead?
65194 * Similar issue as post-increment/post-decrement.
65195 */
65196
65197 /* prevent duk__expr_led() by using a binding power less than anything valid */
65198 if (tok == DUK_TOK_IN && !comp_ctx->curr_func.allow_in) {
65199 return 0;
65200 }
65201
65202 if ((tok == DUK_TOK_DECREMENT || tok == DUK_TOK_INCREMENT) &&
65203 (comp_ctx->curr_token.lineterm)) {
65204 /* '++' or '--' in a post-increment/decrement position,
65205 * and a LineTerminator occurs between the operator and
65206 * the preceding expression. Force the previous expr
65207 * to terminate, in effect treating e.g. "a,b\n++" as
65208 * "a,b;++" (= SyntaxError).
65209 */
65210 return 0;
65211 }
65212
65213 return DUK__TOKEN_LBP_GET_BP(duk__token_lbp[tok]); /* format is bit packed */
65214}
65215
65216/*
65217 * Expression parsing.
65218 *
65219 * Upon entry to 'expr' and its variants, 'curr_tok' is assumed to be the
65220 * first token of the expression. Upon exit, 'curr_tok' will be the first
65221 * token not part of the expression (e.g. semicolon terminating an expression
65222 * statement).
65223 */
65224
65225#define DUK__EXPR_RBP_MASK 0xff
65226#define DUK__EXPR_FLAG_REJECT_IN (1 << 8) /* reject 'in' token (used for for-in) */
65227#define DUK__EXPR_FLAG_ALLOW_EMPTY (1 << 9) /* allow empty expression */
65228#define DUK__EXPR_FLAG_REQUIRE_INIT (1 << 10) /* require initializer for var/const */
65229
65230/* main expression parser function */
65231DUK_LOCAL void duk__expr(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
65232 duk_hthread *thr = comp_ctx->thr;
65233 duk_context *ctx = (duk_context *) thr;
65234 duk_ivalue tmp_alloc; /* 'res' is used for "left", and 'tmp' for "right" */
65235 duk_ivalue *tmp = &tmp_alloc;
65236 duk_small_uint_t rbp;
65237
65238 DUK__RECURSION_INCREASE(comp_ctx, thr);
65239
65240 duk_require_stack(ctx, DUK__PARSE_EXPR_SLOTS);
65241
65242 /* filter out flags from exprtop rbp_flags here to save space */
65243 rbp = rbp_flags & DUK__EXPR_RBP_MASK;
65244
65245 DUK_DDD(DUK_DDDPRINT("duk__expr(), rbp_flags=%ld, rbp=%ld, allow_in=%ld, paren_level=%ld",
65246 (long) rbp_flags, (long) rbp, (long) comp_ctx->curr_func.allow_in,
65247 (long) comp_ctx->curr_func.paren_level));
65248
65249 DUK_MEMZERO(&tmp_alloc, sizeof(tmp_alloc));
65250 tmp->x1.valstack_idx = duk_get_top(ctx);
65251 tmp->x2.valstack_idx = tmp->x1.valstack_idx + 1;
65252 duk_push_undefined(ctx);
65253 duk_push_undefined(ctx);
65254
65255 /* XXX: where to release temp regs in intermediate expressions?
65256 * e.g. 1+2+3 -> don't inflate temp register count when parsing this.
65257 * that particular expression temp regs can be forced here.
65258 */
65259
65260 /* XXX: increase ctx->expr_tokens here for every consumed token
65261 * (this would be a nice statistic)?
65262 */
65263
65264 if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON || comp_ctx->curr_token.t == DUK_TOK_RPAREN) {
65265 /* XXX: possibly incorrect handling of empty expression */
65266 DUK_DDD(DUK_DDDPRINT("empty expression"));
65267 if (!(rbp_flags & DUK__EXPR_FLAG_ALLOW_EMPTY)) {
65268 DUK_ERROR_SYNTAX(thr, DUK_STR_EMPTY_EXPR_NOT_ALLOWED);
65269 }
65270 duk_push_undefined(ctx);
65271 duk__ivalue_plain_fromstack(comp_ctx, res);
65272 goto cleanup;
65273 }
65274
65275 duk__advance(comp_ctx);
65276 duk__expr_nud(comp_ctx, res); /* reuse 'res' as 'left' */
65277 while (rbp < duk__expr_lbp(comp_ctx)) {
65278 duk__advance(comp_ctx);
65279 duk__expr_led(comp_ctx, res, tmp);
65280 duk__copy_ivalue(comp_ctx, tmp, res); /* tmp -> res */
65281 }
65282
65283 cleanup:
65284 /* final result is already in 'res' */
65285
65286 duk_pop_2(ctx);
65287
65288 DUK__RECURSION_DECREASE(comp_ctx, thr);
65289}
65290
65291DUK_LOCAL void duk__exprtop(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
65292 duk_hthread *thr = comp_ctx->thr;
65293
65294 /* Note: these variables must reside in 'curr_func' instead of the global
65295 * context: when parsing function expressions, expression parsing is nested.
65296 */
65297 comp_ctx->curr_func.nud_count = 0;
65298 comp_ctx->curr_func.led_count = 0;
65299 comp_ctx->curr_func.paren_level = 0;
65300 comp_ctx->curr_func.expr_lhs = 1;
65301 comp_ctx->curr_func.allow_in = (rbp_flags & DUK__EXPR_FLAG_REJECT_IN ? 0 : 1);
65302
65303 duk__expr(comp_ctx, res, rbp_flags);
65304
65305 if (!(rbp_flags & DUK__EXPR_FLAG_ALLOW_EMPTY) && duk__expr_is_empty(comp_ctx)) {
65306 DUK_ERROR_SYNTAX(thr, DUK_STR_EMPTY_EXPR_NOT_ALLOWED);
65307 }
65308}
65309
65310/* A bunch of helpers (for size optimization) that combine duk__expr()/duk__exprtop()
65311 * and result conversions.
65312 *
65313 * Each helper needs at least 2-3 calls to make it worth while to wrap.
65314 */
65315
65316#if 0 /* unused */
65317DUK_LOCAL duk_reg_t duk__expr_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
65318 duk__expr(comp_ctx, res, rbp_flags);
65319 return duk__ivalue_toreg(comp_ctx, res);
65320}
65321#endif
65322
65323#if 0 /* unused */
65324DUK_LOCAL duk_reg_t duk__expr_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
65325 duk__expr(comp_ctx, res, rbp_flags);
65326 return duk__ivalue_totemp(comp_ctx, res);
65327}
65328#endif
65329
65330DUK_LOCAL void duk__expr_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_reg_t forced_reg) {
65331 DUK_ASSERT(forced_reg >= 0);
65332 duk__expr(comp_ctx, res, rbp_flags);
65333 duk__ivalue_toforcedreg(comp_ctx, res, forced_reg);
65334}
65335
65336DUK_LOCAL duk_regconst_t duk__expr_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
65337 duk__expr(comp_ctx, res, rbp_flags);
65338 return duk__ivalue_toregconst(comp_ctx, res);
65339}
65340
65341#if 0 /* unused */
65342DUK_LOCAL duk_regconst_t duk__expr_totempconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
65343 duk__expr(comp_ctx, res, rbp_flags);
65344 return duk__ivalue_totempconst(comp_ctx, res);
65345}
65346#endif
65347
65348DUK_LOCAL void duk__expr_toplain(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
65349 duk__expr(comp_ctx, res, rbp_flags);
65350 duk__ivalue_toplain(comp_ctx, res);
65351}
65352
65353DUK_LOCAL void duk__expr_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
65354 duk__expr(comp_ctx, res, rbp_flags);
65355 duk__ivalue_toplain_ignore(comp_ctx, res);
65356}
65357
65358DUK_LOCAL duk_reg_t duk__exprtop_toreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
65359 duk__exprtop(comp_ctx, res, rbp_flags);
65360 return duk__ivalue_toreg(comp_ctx, res);
65361}
65362
65363#if 0 /* unused */
65364DUK_LOCAL duk_reg_t duk__exprtop_totemp(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
65365 duk__exprtop(comp_ctx, res, rbp_flags);
65366 return duk__ivalue_totemp(comp_ctx, res);
65367}
65368#endif
65369
65370DUK_LOCAL void duk__exprtop_toforcedreg(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags, duk_reg_t forced_reg) {
65371 DUK_ASSERT(forced_reg >= 0);
65372 duk__exprtop(comp_ctx, res, rbp_flags);
65373 duk__ivalue_toforcedreg(comp_ctx, res, forced_reg);
65374}
65375
65376DUK_LOCAL duk_regconst_t duk__exprtop_toregconst(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t rbp_flags) {
65377 duk__exprtop(comp_ctx, res, rbp_flags);
65378 return duk__ivalue_toregconst(comp_ctx, res);
65379}
65380
65381#if 0 /* unused */
65382DUK_LOCAL void duk__exprtop_toplain_ignore(duk_compiler_ctx *comp_ctx, duk_ivalue *res, int rbp_flags) {
65383 duk__exprtop(comp_ctx, res, rbp_flags);
65384 duk__ivalue_toplain_ignore(comp_ctx, res);
65385}
65386#endif
65387
65388/*
65389 * Parse an individual source element (top level statement) or a statement.
65390 *
65391 * Handles labeled statements automatically (peeling away labels before
65392 * parsing an expression that follows the label(s)).
65393 *
65394 * Upon entry, 'curr_tok' contains the first token of the statement (parsed
65395 * in "allow regexp literal" mode). Upon exit, 'curr_tok' contains the first
65396 * token following the statement (if the statement has a terminator, this is
65397 * the token after the terminator).
65398 */
65399
65400#define DUK__HAS_VAL (1 << 0) /* stmt has non-empty value */
65401#define DUK__HAS_TERM (1 << 1) /* stmt has explicit/implicit semicolon terminator */
65402#define DUK__ALLOW_AUTO_SEMI_ALWAYS (1 << 2) /* allow automatic semicolon even without lineterm (compatibility) */
65403#define DUK__STILL_PROLOGUE (1 << 3) /* statement does not terminate directive prologue */
65404#define DUK__IS_TERMINAL (1 << 4) /* statement is guaranteed to be terminal (control doesn't flow to next statement) */
65405
65406/* Parse a single variable declaration (e.g. "i" or "i=10"). A leading 'var'
65407 * has already been eaten. These is no return value in 'res', it is used only
65408 * as a temporary.
65409 *
65410 * When called from 'for-in' statement parser, the initializer expression must
65411 * not allow the 'in' token. The caller supply additional expression parsing
65412 * flags (like DUK__EXPR_FLAG_REJECT_IN) in 'expr_flags'.
65413 *
65414 * Finally, out_rc_varname and out_reg_varbind are updated to reflect where
65415 * the identifier is bound:
65416 *
65417 * If register bound: out_reg_varbind >= 0, out_rc_varname == 0 (ignore)
65418 * If not register bound: out_reg_varbind < 0, out_rc_varname >= 0
65419 *
65420 * These allow the caller to use the variable for further assignment, e.g.
65421 * as is done in 'for-in' parsing.
65422 */
65423
65424DUK_LOCAL void duk__parse_var_decl(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags, duk_reg_t *out_reg_varbind, duk_regconst_t *out_rc_varname) {
65425 duk_hthread *thr = comp_ctx->thr;
65426 duk_context *ctx = (duk_context *) thr;
65427 duk_hstring *h_varname;
65428 duk_reg_t reg_varbind;
65429 duk_regconst_t rc_varname;
65430
65431 /* assume 'var' has been eaten */
65432
65433 /* Note: Identifier rejects reserved words */
65434 if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) {
65435 goto syntax_error;
65436 }
65437 h_varname = comp_ctx->curr_token.str1;
65438
65439 DUK_ASSERT(h_varname != NULL);
65440
65441 /* strict mode restrictions (E5 Section 12.2.1) */
65442 if (duk__hstring_is_eval_or_arguments_in_strict_mode(comp_ctx, h_varname)) {
65443 goto syntax_error;
65444 }
65445
65446 /* register declarations in first pass */
65447 if (comp_ctx->curr_func.in_scanning) {
65448 duk_uarridx_t n;
65449 DUK_DDD(DUK_DDDPRINT("register variable declaration %!O in pass 1",
65450 (duk_heaphdr *) h_varname));
65451 n = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.decls_idx);
65452 duk_push_hstring(ctx, h_varname);
65453 duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n);
65454 duk_push_int(ctx, DUK_DECL_TYPE_VAR + (0 << 8));
65455 duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n + 1);
65456 }
65457
65458 duk_push_hstring(ctx, h_varname); /* push before advancing to keep reachable */
65459
65460 /* register binding lookup is based on varmap (even in first pass) */
65461 duk_dup_top(ctx);
65462 (void) duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname);
65463
65464 duk__advance(comp_ctx); /* eat identifier */
65465
65466 if (comp_ctx->curr_token.t == DUK_TOK_EQUALSIGN) {
65467 duk__advance(comp_ctx);
65468
65469 DUK_DDD(DUK_DDDPRINT("vardecl, assign to '%!O' -> reg_varbind=%ld, rc_varname=%ld",
65470 (duk_heaphdr *) h_varname, (long) reg_varbind, (long) rc_varname));
65471
65472 duk__exprtop(comp_ctx, res, DUK__BP_COMMA | expr_flags /*rbp_flags*/); /* AssignmentExpression */
65473
65474 if (reg_varbind >= 0) {
65475 duk__ivalue_toforcedreg(comp_ctx, res, reg_varbind);
65476 } else {
65477 duk_reg_t reg_val;
65478 reg_val = duk__ivalue_toreg(comp_ctx, res);
65479 duk__emit_a_bc(comp_ctx,
65480 DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
65481 (duk_regconst_t) reg_val,
65482 rc_varname);
65483 }
65484 } else {
65485 if (expr_flags & DUK__EXPR_FLAG_REQUIRE_INIT) {
65486 /* Used for minimal 'const': initializer required. */
65487 goto syntax_error;
65488 }
65489 }
65490
65491 duk_pop(ctx); /* pop varname */
65492
65493 *out_rc_varname = rc_varname;
65494 *out_reg_varbind = reg_varbind;
65495
65496 return;
65497
65498 syntax_error:
65499 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_VAR_DECLARATION);
65500}
65501
65502DUK_LOCAL void duk__parse_var_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_small_uint_t expr_flags) {
65503 duk_reg_t reg_varbind;
65504 duk_regconst_t rc_varname;
65505
65506 duk__advance(comp_ctx); /* eat 'var' */
65507
65508 for (;;) {
65509 /* rc_varname and reg_varbind are ignored here */
65510 duk__parse_var_decl(comp_ctx, res, 0 | expr_flags, &reg_varbind, &rc_varname);
65511
65512 if (comp_ctx->curr_token.t != DUK_TOK_COMMA) {
65513 break;
65514 }
65515 duk__advance(comp_ctx);
65516 }
65517}
65518
65519DUK_LOCAL void duk__parse_for_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
65520 duk_hthread *thr = comp_ctx->thr;
65521 duk_context *ctx = (duk_context *) thr;
65522 duk_int_t pc_v34_lhs; /* start variant 3/4 left-hand-side code (L1 in doc/compiler.rst example) */
65523 duk_reg_t temp_reset; /* knock back "next temp" to this whenever possible */
65524 duk_reg_t reg_temps; /* preallocated temporaries (2) for variants 3 and 4 */
65525
65526 DUK_DDD(DUK_DDDPRINT("start parsing a for/for-in statement"));
65527
65528 /* Two temporaries are preallocated here for variants 3 and 4 which need
65529 * registers which are never clobbered by expressions in the loop
65530 * (concretely: for the enumerator object and the next enumerated value).
65531 * Variants 1 and 2 "release" these temps.
65532 */
65533
65534 reg_temps = DUK__ALLOCTEMPS(comp_ctx, 2);
65535
65536 temp_reset = DUK__GETTEMP(comp_ctx);
65537
65538 /*
65539 * For/for-in main variants are:
65540 *
65541 * 1. for (ExpressionNoIn_opt; Expression_opt; Expression_opt) Statement
65542 * 2. for (var VariableDeclarationNoIn; Expression_opt; Expression_opt) Statement
65543 * 3. for (LeftHandSideExpression in Expression) Statement
65544 * 4. for (var VariableDeclarationNoIn in Expression) Statement
65545 *
65546 * Parsing these without arbitrary lookahead or backtracking is relatively
65547 * tricky but we manage to do so for now.
65548 *
65549 * See doc/compiler.rst for a detailed discussion of control flow
65550 * issues, evaluation order issues, etc.
65551 */
65552
65553 duk__advance(comp_ctx); /* eat 'for' */
65554 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
65555
65556 DUK_DDD(DUK_DDDPRINT("detecting for/for-in loop variant, pc=%ld", (long) duk__get_current_pc(comp_ctx)));
65557
65558 /* a label site has been emitted by duk__parse_stmt() automatically
65559 * (it will also emit the ENDLABEL).
65560 */
65561
65562 if (comp_ctx->curr_token.t == DUK_TOK_VAR) {
65563 /*
65564 * Variant 2 or 4
65565 */
65566
65567 duk_reg_t reg_varbind; /* variable binding register if register-bound (otherwise < 0) */
65568 duk_regconst_t rc_varname; /* variable name reg/const, if variable not register-bound */
65569
65570 duk__advance(comp_ctx); /* eat 'var' */
65571 duk__parse_var_decl(comp_ctx, res, DUK__EXPR_FLAG_REJECT_IN, &reg_varbind, &rc_varname);
65572 DUK__SETTEMP(comp_ctx, temp_reset);
65573
65574 if (comp_ctx->curr_token.t == DUK_TOK_IN) {
65575 /*
65576 * Variant 4
65577 */
65578
65579 DUK_DDD(DUK_DDDPRINT("detected for variant 4: for (var VariableDeclarationNoIn in Expression) Statement"));
65580 pc_v34_lhs = duk__get_current_pc(comp_ctx); /* jump is inserted here */
65581 if (reg_varbind >= 0) {
65582 duk__emit_a_bc(comp_ctx,
65583 DUK_OP_LDREG,
65584 (duk_regconst_t) reg_varbind,
65585 (duk_regconst_t) (reg_temps + 0));
65586 } else {
65587 duk__emit_a_bc(comp_ctx,
65588 DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
65589 (duk_regconst_t) (reg_temps + 0),
65590 rc_varname);
65591 }
65592 goto parse_3_or_4;
65593 } else {
65594 /*
65595 * Variant 2
65596 */
65597
65598 DUK_DDD(DUK_DDDPRINT("detected for variant 2: for (var VariableDeclarationNoIn; Expression_opt; Expression_opt) Statement"));
65599 for (;;) {
65600 /* more initializers */
65601 if (comp_ctx->curr_token.t != DUK_TOK_COMMA) {
65602 break;
65603 }
65604 DUK_DDD(DUK_DDDPRINT("variant 2 has another variable initializer"));
65605
65606 duk__advance(comp_ctx); /* eat comma */
65607 duk__parse_var_decl(comp_ctx, res, DUK__EXPR_FLAG_REJECT_IN, &reg_varbind, &rc_varname);
65608 }
65609 goto parse_1_or_2;
65610 }
65611 } else {
65612 /*
65613 * Variant 1 or 3
65614 */
65615
65616 pc_v34_lhs = duk__get_current_pc(comp_ctx); /* jump is inserted here (variant 3) */
65617
65618 /* Note that duk__exprtop() here can clobber any reg above current temp_next,
65619 * so any loop variables (e.g. enumerator) must be "preallocated".
65620 */
65621
65622 /* don't coerce yet to a plain value (variant 3 needs special handling) */
65623 duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR | DUK__EXPR_FLAG_REJECT_IN | DUK__EXPR_FLAG_ALLOW_EMPTY /*rbp_flags*/); /* Expression */
65624 if (comp_ctx->curr_token.t == DUK_TOK_IN) {
65625 /*
65626 * Variant 3
65627 */
65628
65629 /* XXX: need to determine LHS type, and check that it is LHS compatible */
65630 DUK_DDD(DUK_DDDPRINT("detected for variant 3: for (LeftHandSideExpression in Expression) Statement"));
65631 if (duk__expr_is_empty(comp_ctx)) {
65632 goto syntax_error; /* LeftHandSideExpression does not allow empty expression */
65633 }
65634
65635 if (res->t == DUK_IVAL_VAR) {
65636 duk_reg_t reg_varbind;
65637 duk_regconst_t rc_varname;
65638
65639 duk_dup(ctx, res->x1.valstack_idx);
65640 if (duk__lookup_lhs(comp_ctx, &reg_varbind, &rc_varname)) {
65641 duk__emit_a_bc(comp_ctx,
65642 DUK_OP_LDREG,
65643 (duk_regconst_t) reg_varbind,
65644 (duk_regconst_t) (reg_temps + 0));
65645 } else {
65646 duk__emit_a_bc(comp_ctx,
65647 DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
65648 (duk_regconst_t) (reg_temps + 0),
65649 rc_varname);
65650 }
65651 } else if (res->t == DUK_IVAL_PROP) {
65652 /* Don't allow a constant for the object (even for a number etc), as
65653 * it goes into the 'A' field of the opcode.
65654 */
65655 duk_reg_t reg_obj;
65656 duk_regconst_t rc_key;
65657 reg_obj = duk__ispec_toregconst_raw(comp_ctx, &res->x1, -1 /*forced_reg*/, 0 /*flags*/); /* don't allow const */
65658 rc_key = duk__ispec_toregconst_raw(comp_ctx, &res->x2, -1 /*forced_reg*/, DUK__IVAL_FLAG_ALLOW_CONST /*flags*/);
65659 duk__emit_a_b_c(comp_ctx,
65660 DUK_OP_PUTPROP | DUK__EMIT_FLAG_A_IS_SOURCE | DUK__EMIT_FLAG_BC_REGCONST,
65661 (duk_regconst_t) reg_obj,
65662 rc_key,
65663 (duk_regconst_t) (reg_temps + 0));
65664 } else {
65665 duk__ivalue_toplain_ignore(comp_ctx, res); /* just in case */
65666 duk__emit_op_only(comp_ctx,
65667 DUK_OP_INVLHS);
65668 }
65669 goto parse_3_or_4;
65670 } else {
65671 /*
65672 * Variant 1
65673 */
65674
65675 DUK_DDD(DUK_DDDPRINT("detected for variant 1: for (ExpressionNoIn_opt; Expression_opt; Expression_opt) Statement"));
65676 duk__ivalue_toplain_ignore(comp_ctx, res);
65677 goto parse_1_or_2;
65678 }
65679 }
65680
65681 parse_1_or_2:
65682 /*
65683 * Parse variant 1 or 2. The first part expression (which differs
65684 * in the variants) has already been parsed and its code emitted.
65685 *
65686 * reg_temps + 0: unused
65687 * reg_temps + 1: unused
65688 */
65689 {
65690 duk_regconst_t rc_cond;
65691 duk_int_t pc_l1, pc_l2, pc_l3, pc_l4;
65692 duk_int_t pc_jumpto_l3, pc_jumpto_l4;
65693 duk_bool_t expr_c_empty;
65694
65695 DUK_DDD(DUK_DDDPRINT("shared code for parsing variants 1 and 2"));
65696
65697 /* "release" preallocated temps since we won't need them */
65698 temp_reset = reg_temps + 0;
65699 DUK__SETTEMP(comp_ctx, temp_reset);
65700
65701 duk__advance_expect(comp_ctx, DUK_TOK_SEMICOLON);
65702
65703 pc_l1 = duk__get_current_pc(comp_ctx);
65704 duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR | DUK__EXPR_FLAG_ALLOW_EMPTY /*rbp_flags*/); /* Expression_opt */
65705 if (duk__expr_is_empty(comp_ctx)) {
65706 /* no need to coerce */
65707 pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx); /* to body */
65708 pc_jumpto_l4 = -1; /* omitted */
65709 } else {
65710 rc_cond = duk__ivalue_toregconst(comp_ctx, res);
65711 duk__emit_if_false_skip(comp_ctx, rc_cond);
65712 pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx); /* to body */
65713 pc_jumpto_l4 = duk__emit_jump_empty(comp_ctx); /* to exit */
65714 }
65715 DUK__SETTEMP(comp_ctx, temp_reset);
65716
65717 duk__advance_expect(comp_ctx, DUK_TOK_SEMICOLON);
65718
65719 pc_l2 = duk__get_current_pc(comp_ctx);
65720 duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR | DUK__EXPR_FLAG_ALLOW_EMPTY /*rbp_flags*/); /* Expression_opt */
65721 if (duk__expr_is_empty(comp_ctx)) {
65722 /* no need to coerce */
65723 expr_c_empty = 1;
65724 /* JUMP L1 omitted */
65725 } else {
65726 duk__ivalue_toplain_ignore(comp_ctx, res);
65727 expr_c_empty = 0;
65728 duk__emit_jump(comp_ctx, pc_l1);
65729 }
65730 DUK__SETTEMP(comp_ctx, temp_reset);
65731
65732 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
65733
65734 pc_l3 = duk__get_current_pc(comp_ctx);
65735 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
65736 if (expr_c_empty) {
65737 duk__emit_jump(comp_ctx, pc_l1);
65738 } else {
65739 duk__emit_jump(comp_ctx, pc_l2);
65740 }
65741 /* temp reset is not necessary after duk__parse_stmt(), which already does it */
65742
65743 pc_l4 = duk__get_current_pc(comp_ctx);
65744
65745 DUK_DDD(DUK_DDDPRINT("patching jumps: jumpto_l3: %ld->%ld, jumpto_l4: %ld->%ld, "
65746 "break: %ld->%ld, continue: %ld->%ld",
65747 (long) pc_jumpto_l3, (long) pc_l3, (long) pc_jumpto_l4, (long) pc_l4,
65748 (long) (pc_label_site + 1), (long) pc_l4, (long) (pc_label_site + 2), (long) pc_l2));
65749
65750 duk__patch_jump(comp_ctx, pc_jumpto_l3, pc_l3);
65751 duk__patch_jump(comp_ctx, pc_jumpto_l4, pc_l4);
65752 duk__patch_jump(comp_ctx,
65753 pc_label_site + 1,
65754 pc_l4); /* break jump */
65755 duk__patch_jump(comp_ctx,
65756 pc_label_site + 2,
65757 expr_c_empty ? pc_l1 : pc_l2); /* continue jump */
65758 }
65759 goto finished;
65760
65761 parse_3_or_4:
65762 /*
65763 * Parse variant 3 or 4.
65764 *
65765 * For variant 3 (e.g. "for (A in C) D;") the code for A (except the
65766 * final property/variable write) has already been emitted. The first
65767 * instruction of that code is at pc_v34_lhs; a JUMP needs to be inserted
65768 * there to satisfy control flow needs.
65769 *
65770 * For variant 4, if the variable declaration had an initializer
65771 * (e.g. "for (var A = B in C) D;") the code for the assignment
65772 * (B) has already been emitted.
65773 *
65774 * Variables set before entering here:
65775 *
65776 * pc_v34_lhs: insert a "JUMP L2" here (see doc/compiler.rst example).
65777 * reg_temps + 0: iteration target value (written to LHS)
65778 * reg_temps + 1: enumerator object
65779 */
65780 {
65781 duk_int_t pc_l1, pc_l2, pc_l3, pc_l4, pc_l5;
65782 duk_int_t pc_jumpto_l2, pc_jumpto_l3, pc_jumpto_l4, pc_jumpto_l5;
65783 duk_reg_t reg_target;
65784
65785 DUK_DDD(DUK_DDDPRINT("shared code for parsing variants 3 and 4, pc_v34_lhs=%ld", (long) pc_v34_lhs));
65786
65787 DUK__SETTEMP(comp_ctx, temp_reset);
65788
65789 /* First we need to insert a jump in the middle of previously
65790 * emitted code to get the control flow right. No jumps can
65791 * cross the position where the jump is inserted. See doc/compiler.rst
65792 * for discussion on the intricacies of control flow and side effects
65793 * for variants 3 and 4.
65794 */
65795
65796 duk__insert_jump_entry(comp_ctx, pc_v34_lhs);
65797 pc_jumpto_l2 = pc_v34_lhs; /* inserted jump */
65798 pc_l1 = pc_v34_lhs + 1; /* +1, right after inserted jump */
65799
65800 /* The code for writing reg_temps + 0 to the left hand side has already
65801 * been emitted.
65802 */
65803
65804 pc_jumpto_l3 = duk__emit_jump_empty(comp_ctx); /* -> loop body */
65805
65806 duk__advance(comp_ctx); /* eat 'in' */
65807
65808 /* Parse enumeration target and initialize enumerator. For 'null' and 'undefined',
65809 * INITENUM will creates a 'null' enumerator which works like an empty enumerator
65810 * (E5 Section 12.6.4, step 3). Note that INITENUM requires the value to be in a
65811 * register (constant not allowed).
65812 */
65813
65814 pc_l2 = duk__get_current_pc(comp_ctx);
65815 reg_target = duk__exprtop_toreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/); /* Expression */
65816 duk__emit_b_c(comp_ctx,
65817 DUK_OP_INITENUM | DUK__EMIT_FLAG_B_IS_TARGET,
65818 (duk_regconst_t) (reg_temps + 1),
65819 (duk_regconst_t) reg_target);
65820 pc_jumpto_l4 = duk__emit_jump_empty(comp_ctx);
65821 DUK__SETTEMP(comp_ctx, temp_reset);
65822
65823 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
65824
65825 pc_l3 = duk__get_current_pc(comp_ctx);
65826 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
65827 /* temp reset is not necessary after duk__parse_stmt(), which already does it */
65828
65829 /* NEXTENUM needs a jump slot right after the main opcode.
65830 * We need the code emitter to reserve the slot: if there's
65831 * target shuffling, the target shuffle opcodes must happen
65832 * after the jump slot (for NEXTENUM the shuffle opcodes are
65833 * not needed if the enum is finished).
65834 */
65835 pc_l4 = duk__get_current_pc(comp_ctx);
65836 duk__emit_b_c(comp_ctx,
65837 DUK_OP_NEXTENUM | DUK__EMIT_FLAG_B_IS_TARGET | DUK__EMIT_FLAG_RESERVE_JUMPSLOT,
65838 (duk_regconst_t) (reg_temps + 0),
65839 (duk_regconst_t) (reg_temps + 1));
65840 pc_jumpto_l5 = comp_ctx->emit_jumpslot_pc; /* NEXTENUM jump slot: executed when enum finished */
65841 duk__emit_jump(comp_ctx, pc_l1); /* jump to next loop, using reg_v34_iter as iterated value */
65842
65843 pc_l5 = duk__get_current_pc(comp_ctx);
65844
65845 /* XXX: since the enumerator may be a memory expensive object,
65846 * perhaps clear it explicitly here? If so, break jump must
65847 * go through this clearing operation.
65848 */
65849
65850 DUK_DDD(DUK_DDDPRINT("patching jumps: jumpto_l2: %ld->%ld, jumpto_l3: %ld->%ld, "
65851 "jumpto_l4: %ld->%ld, jumpto_l5: %ld->%ld, "
65852 "break: %ld->%ld, continue: %ld->%ld",
65853 (long) pc_jumpto_l2, (long) pc_l2, (long) pc_jumpto_l3, (long) pc_l3,
65854 (long) pc_jumpto_l4, (long) pc_l4, (long) pc_jumpto_l5, (long) pc_l5,
65855 (long) (pc_label_site + 1), (long) pc_l5, (long) (pc_label_site + 2), (long) pc_l4));
65856
65857 duk__patch_jump(comp_ctx, pc_jumpto_l2, pc_l2);
65858 duk__patch_jump(comp_ctx, pc_jumpto_l3, pc_l3);
65859 duk__patch_jump(comp_ctx, pc_jumpto_l4, pc_l4);
65860 duk__patch_jump(comp_ctx, pc_jumpto_l5, pc_l5);
65861 duk__patch_jump(comp_ctx, pc_label_site + 1, pc_l5); /* break jump */
65862 duk__patch_jump(comp_ctx, pc_label_site + 2, pc_l4); /* continue jump */
65863 }
65864 goto finished;
65865
65866 finished:
65867 DUK_DDD(DUK_DDDPRINT("end parsing a for/for-in statement"));
65868 return;
65869
65870 syntax_error:
65871 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_FOR);
65872}
65873
65874DUK_LOCAL void duk__parse_switch_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
65875 duk_hthread *thr = comp_ctx->thr;
65876 duk_reg_t temp_at_loop;
65877 duk_regconst_t rc_switch; /* reg/const for switch value */
65878 duk_regconst_t rc_case; /* reg/const for case value */
65879 duk_reg_t reg_temp; /* general temp register */
65880 duk_int_t pc_prevcase = -1;
65881 duk_int_t pc_prevstmt = -1;
65882 duk_int_t pc_default = -1; /* -1 == not set, -2 == pending (next statement list) */
65883
65884 /* Note: negative pc values are ignored when patching jumps, so no explicit checks needed */
65885
65886 /*
65887 * Switch is pretty complicated because of several conflicting concerns:
65888 *
65889 * - Want to generate code without an intermediate representation,
65890 * i.e., in one go
65891 *
65892 * - Case selectors are expressions, not values, and may thus e.g. throw
65893 * exceptions (which causes evaluation order concerns)
65894 *
65895 * - Evaluation semantics of case selectors and default clause need to be
65896 * carefully implemented to provide correct behavior even with case value
65897 * side effects
65898 *
65899 * - Fall through case and default clauses; avoiding dead JUMPs if case
65900 * ends with an unconditional jump (a break or a continue)
65901 *
65902 * - The same case value may occur multiple times, but evaluation rules
65903 * only process the first match before switching to a "propagation" mode
65904 * where case values are no longer evaluated
65905 *
65906 * See E5 Section 12.11. Also see doc/compiler.rst for compilation
65907 * discussion.
65908 */
65909
65910 duk__advance(comp_ctx);
65911 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
65912 rc_switch = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
65913 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
65914 duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
65915
65916 DUK_DDD(DUK_DDDPRINT("switch value in register %ld", (long) rc_switch));
65917
65918 temp_at_loop = DUK__GETTEMP(comp_ctx);
65919
65920 for (;;) {
65921 duk_int_t num_stmts;
65922 duk_small_int_t tok;
65923
65924 /* sufficient for keeping temp reg numbers in check */
65925 DUK__SETTEMP(comp_ctx, temp_at_loop);
65926
65927 if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
65928 break;
65929 }
65930
65931 /*
65932 * Parse a case or default clause.
65933 */
65934
65935 if (comp_ctx->curr_token.t == DUK_TOK_CASE) {
65936 /*
65937 * Case clause.
65938 *
65939 * Note: cannot use reg_case as a temp register (for SEQ target)
65940 * because it may be a constant.
65941 */
65942
65943 duk__patch_jump_here(comp_ctx, pc_prevcase); /* chain jumps for case
65944 * evaluation and checking
65945 */
65946
65947 duk__advance(comp_ctx);
65948 rc_case = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
65949 duk__advance_expect(comp_ctx, DUK_TOK_COLON);
65950
65951 reg_temp = DUK__ALLOCTEMP(comp_ctx);
65952 duk__emit_a_b_c(comp_ctx,
65953 DUK_OP_SEQ | DUK__EMIT_FLAG_BC_REGCONST,
65954 (duk_regconst_t) reg_temp,
65955 rc_switch,
65956 rc_case);
65957 duk__emit_if_true_skip(comp_ctx, (duk_regconst_t) reg_temp);
65958
65959 /* jump to next case clause */
65960 pc_prevcase = duk__emit_jump_empty(comp_ctx); /* no match, next case */
65961
65962 /* statements go here (if any) on next loop */
65963 } else if (comp_ctx->curr_token.t == DUK_TOK_DEFAULT) {
65964 /*
65965 * Default clause.
65966 */
65967
65968 if (pc_default >= 0) {
65969 goto syntax_error;
65970 }
65971 duk__advance(comp_ctx);
65972 duk__advance_expect(comp_ctx, DUK_TOK_COLON);
65973
65974 /* Fix for https://github.com/svaarala/duktape/issues/155:
65975 * If 'default' is first clause (detected by pc_prevcase < 0)
65976 * we need to ensure we stay in the matching chain.
65977 */
65978 if (pc_prevcase < 0) {
65979 DUK_DD(DUK_DDPRINT("default clause is first, emit prevcase jump"));
65980 pc_prevcase = duk__emit_jump_empty(comp_ctx);
65981 }
65982
65983 /* default clause matches next statement list (if any) */
65984 pc_default = -2;
65985 } else {
65986 /* Code is not accepted before the first case/default clause */
65987 goto syntax_error;
65988 }
65989
65990 /*
65991 * Parse code after the clause. Possible terminators are
65992 * 'case', 'default', and '}'.
65993 *
65994 * Note that there may be no code at all, not even an empty statement,
65995 * between case clauses. This must be handled just like an empty statement
65996 * (omitting seemingly pointless JUMPs), to avoid situations like
65997 * test-bug-case-fallthrough.js.
65998 */
65999
66000 num_stmts = 0;
66001 if (pc_default == -2) {
66002 pc_default = duk__get_current_pc(comp_ctx);
66003 }
66004
66005 /* Note: this is correct even for default clause statements:
66006 * they participate in 'fall-through' behavior even if the
66007 * default clause is in the middle.
66008 */
66009 duk__patch_jump_here(comp_ctx, pc_prevstmt); /* chain jumps for 'fall-through'
66010 * after a case matches.
66011 */
66012
66013 for (;;) {
66014 tok = comp_ctx->curr_token.t;
66015 if (tok == DUK_TOK_CASE || tok == DUK_TOK_DEFAULT ||
66016 tok == DUK_TOK_RCURLY) {
66017 break;
66018 }
66019 num_stmts++;
66020 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
66021 }
66022
66023 /* fall-through jump to next code of next case (backpatched) */
66024 pc_prevstmt = duk__emit_jump_empty(comp_ctx);
66025
66026 /* XXX: would be nice to omit this jump when the jump is not
66027 * reachable, at least in the obvious cases (such as the case
66028 * ending with a 'break'.
66029 *
66030 * Perhaps duk__parse_stmt() could provide some info on whether
66031 * the statement is a "dead end"?
66032 *
66033 * If implemented, just set pc_prevstmt to -1 when not needed.
66034 */
66035 }
66036
66037 DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RCURLY);
66038 duk__advance(comp_ctx);
66039
66040 /* default case control flow patchup; note that if pc_prevcase < 0
66041 * (i.e. no case clauses), control enters default case automatically.
66042 */
66043 if (pc_default >= 0) {
66044 /* default case exists: go there if no case matches */
66045 duk__patch_jump(comp_ctx, pc_prevcase, pc_default);
66046 } else {
66047 /* default case does not exist, or no statements present
66048 * after default case: finish case evaluation
66049 */
66050 duk__patch_jump_here(comp_ctx, pc_prevcase);
66051 }
66052
66053 /* fall-through control flow patchup; note that pc_prevstmt may be
66054 * < 0 (i.e. no case clauses), in which case this is a no-op.
66055 */
66056 duk__patch_jump_here(comp_ctx, pc_prevstmt);
66057
66058 /* continue jump not patched, an INVALID opcode remains there */
66059 duk__patch_jump_here(comp_ctx, pc_label_site + 1); /* break jump */
66060
66061 /* Note: 'fast' breaks will jump to pc_label_site + 1, which will
66062 * then jump here. The double jump will be eliminated by a
66063 * peephole pass, resulting in an optimal jump here. The label
66064 * site jumps will remain in bytecode and will waste code size.
66065 */
66066
66067 return;
66068
66069 syntax_error:
66070 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_SWITCH);
66071}
66072
66073DUK_LOCAL void duk__parse_if_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
66074 duk_reg_t temp_reset;
66075 duk_regconst_t rc_cond;
66076 duk_int_t pc_jump_false;
66077
66078 DUK_DDD(DUK_DDDPRINT("begin parsing if statement"));
66079
66080 temp_reset = DUK__GETTEMP(comp_ctx);
66081
66082 duk__advance(comp_ctx); /* eat 'if' */
66083 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
66084
66085 rc_cond = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
66086 duk__emit_if_true_skip(comp_ctx, rc_cond);
66087 pc_jump_false = duk__emit_jump_empty(comp_ctx); /* jump to end or else part */
66088 DUK__SETTEMP(comp_ctx, temp_reset);
66089
66090 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
66091
66092 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
66093
66094 /* The 'else' ambiguity is resolved by 'else' binding to the innermost
66095 * construct, so greedy matching is correct here.
66096 */
66097
66098 if (comp_ctx->curr_token.t == DUK_TOK_ELSE) {
66099 duk_int_t pc_jump_end;
66100
66101 DUK_DDD(DUK_DDDPRINT("if has else part"));
66102
66103 duk__advance(comp_ctx);
66104
66105 pc_jump_end = duk__emit_jump_empty(comp_ctx); /* jump from true part to end */
66106 duk__patch_jump_here(comp_ctx, pc_jump_false);
66107
66108 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
66109
66110 duk__patch_jump_here(comp_ctx, pc_jump_end);
66111 } else {
66112 DUK_DDD(DUK_DDDPRINT("if does not have else part"));
66113
66114 duk__patch_jump_here(comp_ctx, pc_jump_false);
66115 }
66116
66117 DUK_DDD(DUK_DDDPRINT("end parsing if statement"));
66118}
66119
66120DUK_LOCAL void duk__parse_do_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
66121 duk_regconst_t rc_cond;
66122 duk_int_t pc_start;
66123
66124 DUK_DDD(DUK_DDDPRINT("begin parsing do statement"));
66125
66126 duk__advance(comp_ctx); /* eat 'do' */
66127
66128 pc_start = duk__get_current_pc(comp_ctx);
66129 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
66130 duk__patch_jump_here(comp_ctx, pc_label_site + 2); /* continue jump */
66131
66132 duk__advance_expect(comp_ctx, DUK_TOK_WHILE);
66133 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
66134
66135 rc_cond = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
66136 duk__emit_if_false_skip(comp_ctx, rc_cond);
66137 duk__emit_jump(comp_ctx, pc_start);
66138 /* no need to reset temps, as we're finished emitting code */
66139
66140 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
66141
66142 duk__patch_jump_here(comp_ctx, pc_label_site + 1); /* break jump */
66143
66144 DUK_DDD(DUK_DDDPRINT("end parsing do statement"));
66145}
66146
66147DUK_LOCAL void duk__parse_while_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_int_t pc_label_site) {
66148 duk_reg_t temp_reset;
66149 duk_regconst_t rc_cond;
66150 duk_int_t pc_start;
66151 duk_int_t pc_jump_false;
66152
66153 DUK_DDD(DUK_DDDPRINT("begin parsing while statement"));
66154
66155 temp_reset = DUK__GETTEMP(comp_ctx);
66156
66157 duk__advance(comp_ctx); /* eat 'while' */
66158
66159 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
66160
66161 pc_start = duk__get_current_pc(comp_ctx);
66162 duk__patch_jump_here(comp_ctx, pc_label_site + 2); /* continue jump */
66163
66164 rc_cond = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
66165 duk__emit_if_true_skip(comp_ctx, rc_cond);
66166 pc_jump_false = duk__emit_jump_empty(comp_ctx);
66167 DUK__SETTEMP(comp_ctx, temp_reset);
66168
66169 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
66170
66171 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
66172 duk__emit_jump(comp_ctx, pc_start);
66173
66174 duk__patch_jump_here(comp_ctx, pc_jump_false);
66175 duk__patch_jump_here(comp_ctx, pc_label_site + 1); /* break jump */
66176
66177 DUK_DDD(DUK_DDDPRINT("end parsing while statement"));
66178}
66179
66180DUK_LOCAL void duk__parse_break_or_continue_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
66181 duk_hthread *thr = comp_ctx->thr;
66182 duk_bool_t is_break = (comp_ctx->curr_token.t == DUK_TOK_BREAK);
66183 duk_int_t label_id;
66184 duk_int_t label_catch_depth;
66185 duk_int_t label_pc; /* points to LABEL; pc+1 = jump site for break; pc+2 = jump site for continue */
66186 duk_bool_t label_is_closest;
66187
66188 DUK_UNREF(res);
66189
66190 duk__advance(comp_ctx); /* eat 'break' or 'continue' */
66191
66192 if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON || /* explicit semi follows */
66193 comp_ctx->curr_token.lineterm || /* automatic semi will be inserted */
66194 comp_ctx->curr_token.allow_auto_semi) { /* automatic semi will be inserted */
66195 /* break/continue without label */
66196
66197 duk__lookup_active_label(comp_ctx, DUK_HTHREAD_STRING_EMPTY_STRING(thr), is_break, &label_id, &label_catch_depth, &label_pc, &label_is_closest);
66198 } else if (comp_ctx->curr_token.t == DUK_TOK_IDENTIFIER) {
66199 /* break/continue with label (label cannot be a reserved word, production is 'Identifier' */
66200 DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
66201 duk__lookup_active_label(comp_ctx, comp_ctx->curr_token.str1, is_break, &label_id, &label_catch_depth, &label_pc, &label_is_closest);
66202 duk__advance(comp_ctx);
66203 } else {
66204 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_BREAK_CONT_LABEL);
66205 }
66206
66207 /* Use a fast break/continue when possible. A fast break/continue is
66208 * just a jump to the LABEL break/continue jump slot, which then jumps
66209 * to an appropriate place (for break, going through ENDLABEL correctly).
66210 * The peephole optimizer will optimize the jump to a direct one.
66211 */
66212
66213 if (label_catch_depth == comp_ctx->curr_func.catch_depth &&
66214 label_is_closest) {
66215 DUK_DDD(DUK_DDDPRINT("break/continue: is_break=%ld, label_id=%ld, label_is_closest=%ld, "
66216 "label_catch_depth=%ld, catch_depth=%ld "
66217 "-> use fast variant (direct jump)",
66218 (long) is_break, (long) label_id, (long) label_is_closest,
66219 (long) label_catch_depth, (long) comp_ctx->curr_func.catch_depth));
66220
66221 duk__emit_jump(comp_ctx, label_pc + (is_break ? 1 : 2));
66222 } else {
66223 DUK_DDD(DUK_DDDPRINT("break/continue: is_break=%ld, label_id=%ld, label_is_closest=%ld, "
66224 "label_catch_depth=%ld, catch_depth=%ld "
66225 "-> use slow variant (longjmp)",
66226 (long) is_break, (long) label_id, (long) label_is_closest,
66227 (long) label_catch_depth, (long) comp_ctx->curr_func.catch_depth));
66228
66229 duk__emit_bc(comp_ctx,
66230 is_break ? DUK_OP_BREAK : DUK_OP_CONTINUE,
66231 (duk_regconst_t) label_id);
66232 }
66233}
66234
66235DUK_LOCAL void duk__parse_return_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
66236 duk_hthread *thr = comp_ctx->thr;
66237 duk_regconst_t rc_val;
66238
66239 duk__advance(comp_ctx); /* eat 'return' */
66240
66241 /* A 'return' statement is only allowed inside an actual function body,
66242 * not as part of eval or global code.
66243 */
66244 if (!comp_ctx->curr_func.is_function) {
66245 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_RETURN);
66246 }
66247
66248 if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON || /* explicit semi follows */
66249 comp_ctx->curr_token.lineterm || /* automatic semi will be inserted */
66250 comp_ctx->curr_token.allow_auto_semi) { /* automatic semi will be inserted */
66251 DUK_DDD(DUK_DDDPRINT("empty return value -> undefined"));
66252 duk__emit_op_only(comp_ctx, DUK_OP_RETUNDEF);
66253 } else {
66254 duk_int_t pc_before_expr;
66255 duk_int_t pc_after_expr;
66256
66257 DUK_DDD(DUK_DDDPRINT("return with a value"));
66258
66259 DUK_UNREF(pc_before_expr);
66260 DUK_UNREF(pc_after_expr);
66261
66262 pc_before_expr = duk__get_current_pc(comp_ctx);
66263 rc_val = duk__exprtop_toregconst(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
66264 pc_after_expr = duk__get_current_pc(comp_ctx);
66265
66266 /* Tail call check: if last opcode emitted was CALL, and
66267 * the context allows it, change the CALL to TAILCALL.
66268 * This doesn't guarantee that a tail call will be allowed at
66269 * runtime, so the RETURN must still be emitted. (Duktape
66270 * 0.10.0 avoided this and simulated a RETURN if a tail call
66271 * couldn't be used at runtime; but this didn't work
66272 * correctly with a thread yield/resume, see
66273 * test-bug-tailcall-thread-yield-resume.js for discussion.)
66274 *
66275 * In addition to the last opcode being CALL, we also need to
66276 * be sure that 'rc_val' is the result register of the CALL.
66277 * For instance, for the expression 'return 0, (function ()
66278 * { return 1; }), 2' the last opcode emitted is CALL (no
66279 * bytecode is emitted for '2') but 'rc_val' indicates
66280 * constant '2'. Similarly if '2' is replaced by a register
66281 * bound variable, no opcodes are emitted but tail call would
66282 * be incorrect.
66283 *
66284 * This is tricky and easy to get wrong. It would be best to
66285 * track enough expression metadata to check that 'rc_val' came
66286 * from that last CALL instruction. We don't have that metadata
66287 * now, so we check that 'rc_val' is a temporary register result
66288 * (not a constant or a register bound variable). There should
66289 * be no way currently for 'rc_val' to be a temporary for an
66290 * expression following the CALL instruction without emitting
66291 * some opcodes following the CALL. This proxy check is used
66292 * below.
66293 *
66294 * See: test-bug-comma-expr-gh131.js.
66295 *
66296 * The non-standard 'caller' property disables tail calls
66297 * because they pose some special cases which haven't been
66298 * fixed yet.
66299 */
66300
66301#if defined(DUK_USE_TAILCALL)
66302 if (comp_ctx->curr_func.catch_depth == 0 && /* no catchers */
66303 pc_after_expr > pc_before_expr) { /* at least one opcode emitted */
66304 duk_compiler_instr *instr;
66305 duk_instr_t ins;
66306 duk_small_uint_t op;
66307
66308 instr = duk__get_instr_ptr(comp_ctx, pc_after_expr - 1);
66309 DUK_ASSERT(instr != NULL);
66310
66311 ins = instr->ins;
66312 op = (duk_small_uint_t) DUK_DEC_OP(ins);
66313 if (op == DUK_OP_CALL &&
66314 DUK__ISTEMP(comp_ctx, rc_val) /* see above */) {
66315 DUK_DDD(DUK_DDDPRINT("return statement detected a tail call opportunity: "
66316 "catch depth is 0, duk__exprtop() emitted >= 1 instructions, "
66317 "and last instruction is a CALL "
66318 "-> change to TAILCALL"));
66319 ins = (ins & ~DUK_BC_SHIFTED_MASK_OP) | (DUK_OP_TAILCALL << DUK_BC_SHIFT_OP);
66320 instr->ins = ins;
66321 }
66322 }
66323#endif /* DUK_USE_TAILCALL */
66324
66325 if (DUK__ISREG(rc_val)) {
66326 duk__emit_bc(comp_ctx, DUK_OP_RETREG, rc_val);
66327 } else {
66328 rc_val = DUK__REMOVECONST(rc_val);
66329 if (duk__const_needs_refcount(comp_ctx, rc_val)) {
66330 duk__emit_bc(comp_ctx, DUK_OP_RETCONST, rc_val);
66331 } else {
66332 duk__emit_bc(comp_ctx, DUK_OP_RETCONSTN, rc_val);
66333 }
66334 }
66335 }
66336}
66337
66338DUK_LOCAL void duk__parse_throw_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
66339 duk_reg_t reg_val;
66340
66341 duk__advance(comp_ctx); /* eat 'throw' */
66342
66343 /* Unlike break/continue, throw statement does not allow an empty value. */
66344
66345 if (comp_ctx->curr_token.lineterm) {
66346 DUK_ERROR_SYNTAX(comp_ctx->thr, DUK_STR_INVALID_THROW);
66347 }
66348
66349 reg_val = duk__exprtop_toreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
66350 duk__emit_bc(comp_ctx,
66351 DUK_OP_THROW,
66352 (duk_regconst_t) reg_val);
66353}
66354
66355DUK_LOCAL void duk__parse_try_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
66356 duk_hthread *thr = comp_ctx->thr;
66357 duk_context *ctx = (duk_context *) thr;
66358 duk_reg_t reg_catch; /* reg_catch+0 and reg_catch+1 are reserved for TRYCATCH */
66359 duk_regconst_t rc_varname = 0;
66360 duk_small_uint_t trycatch_flags = 0;
66361 duk_int_t pc_ldconst = -1;
66362 duk_int_t pc_trycatch = -1;
66363 duk_int_t pc_catch = -1;
66364 duk_int_t pc_finally = -1;
66365
66366 DUK_UNREF(res);
66367
66368 /*
66369 * See the following documentation for discussion:
66370 *
66371 * doc/execution.rst: control flow details
66372 *
66373 * Try, catch, and finally "parts" are Blocks, not Statements, so
66374 * they must always be delimited by curly braces. This is unlike e.g.
66375 * the if statement, which accepts any Statement. This eliminates any
66376 * questions of matching parts of nested try statements. The Block
66377 * parsing is implemented inline here (instead of calling out).
66378 *
66379 * Finally part has a 'let scoped' variable, which requires a few kinks
66380 * here.
66381 */
66382
66383 comp_ctx->curr_func.catch_depth++;
66384
66385 duk__advance(comp_ctx); /* eat 'try' */
66386
66387 reg_catch = DUK__ALLOCTEMPS(comp_ctx, 2);
66388
66389 /* The target for this LDCONST may need output shuffling, but we assume
66390 * that 'pc_ldconst' will be the LDCONST that we can patch later. This
66391 * should be the case because there's no input shuffling. (If there's
66392 * no catch clause, this LDCONST will be replaced with a NOP.)
66393 */
66394 pc_ldconst = duk__get_current_pc(comp_ctx);
66395 duk__emit_a_bc(comp_ctx, DUK_OP_LDCONST, reg_catch, 0 /*patched later*/);
66396
66397 pc_trycatch = duk__get_current_pc(comp_ctx);
66398 duk__emit_invalid(comp_ctx); /* TRYCATCH, cannot emit now (not enough info) */
66399 duk__emit_invalid(comp_ctx); /* jump for 'catch' case */
66400 duk__emit_invalid(comp_ctx); /* jump for 'finally' case or end (if no finally) */
66401
66402 /* try part */
66403 duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
66404 duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
66405 /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
66406 duk__emit_op_only(comp_ctx,
66407 DUK_OP_ENDTRY);
66408
66409 if (comp_ctx->curr_token.t == DUK_TOK_CATCH) {
66410 /*
66411 * The catch variable must be updated to reflect the new allocated
66412 * register for the duration of the catch clause. We need to store
66413 * and restore the original value for the varmap entry (if any).
66414 */
66415
66416 /*
66417 * Note: currently register bindings must be fixed for the entire
66418 * function. So, even though the catch variable is in a register
66419 * we know, we must use an explicit environment record and slow path
66420 * accesses to read/write the catch binding to make closures created
66421 * within the catch clause work correctly. This restriction should
66422 * be fixable (at least in common cases) later.
66423 *
66424 * See: test-bug-catch-binding-2.js.
66425 *
66426 * XXX: improve to get fast path access to most catch clauses.
66427 */
66428
66429 duk_hstring *h_var;
66430 duk_int_t varmap_value; /* for storing/restoring the varmap binding for catch variable */
66431
66432 DUK_DDD(DUK_DDDPRINT("stack top at start of catch clause: %ld", (long) duk_get_top(ctx)));
66433
66434 trycatch_flags |= DUK_BC_TRYCATCH_FLAG_HAVE_CATCH;
66435
66436 pc_catch = duk__get_current_pc(comp_ctx);
66437
66438 duk__advance(comp_ctx);
66439 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
66440
66441 if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) {
66442 /* Identifier, i.e. don't allow reserved words */
66443 goto syntax_error;
66444 }
66445 h_var = comp_ctx->curr_token.str1;
66446 DUK_ASSERT(h_var != NULL);
66447
66448 duk_push_hstring(ctx, h_var); /* keep in on valstack, use borrowed ref below */
66449
66450 if (comp_ctx->curr_func.is_strict &&
66451 ((h_var == DUK_HTHREAD_STRING_EVAL(thr)) ||
66452 (h_var == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)))) {
66453 DUK_DDD(DUK_DDDPRINT("catch identifier 'eval' or 'arguments' in strict mode -> SyntaxError"));
66454 goto syntax_error;
66455 }
66456
66457 duk_dup_top(ctx);
66458 rc_varname = duk__getconst(comp_ctx);
66459 DUK_DDD(DUK_DDDPRINT("catch clause, rc_varname=0x%08lx (%ld)",
66460 (unsigned long) rc_varname, (long) rc_varname));
66461
66462 duk__advance(comp_ctx);
66463 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
66464
66465 duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
66466
66467 DUK_DDD(DUK_DDDPRINT("varmap before modifying for catch clause: %!iT",
66468 (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx)));
66469
66470 duk_dup_top(ctx);
66471 duk_get_prop(ctx, comp_ctx->curr_func.varmap_idx);
66472 if (duk_is_undefined(ctx, -1)) {
66473 varmap_value = -2;
66474 } else if (duk_is_null(ctx, -1)) {
66475 varmap_value = -1;
66476 } else {
66477 DUK_ASSERT(duk_is_number(ctx, -1));
66478 varmap_value = duk_get_int(ctx, -1);
66479 DUK_ASSERT(varmap_value >= 0);
66480 }
66481 duk_pop(ctx);
66482
66483#if 0
66484 /* It'd be nice to do something like this - but it doesn't
66485 * work for closures created inside the catch clause.
66486 */
66487 duk_dup_top(ctx);
66488 duk_push_int(ctx, (duk_int_t) (reg_catch + 0));
66489 duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx);
66490#endif
66491 duk_dup_top(ctx);
66492 duk_push_null(ctx);
66493 duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx);
66494
66495 duk__emit_a_bc(comp_ctx,
66496 DUK_OP_PUTVAR | DUK__EMIT_FLAG_A_IS_SOURCE,
66497 (duk_regconst_t) (reg_catch + 0) /*value*/,
66498 rc_varname /*varname*/);
66499
66500 DUK_DDD(DUK_DDDPRINT("varmap before parsing catch clause: %!iT",
66501 (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx)));
66502
66503 duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
66504 /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
66505
66506 if (varmap_value == -2) {
66507 /* not present */
66508 duk_del_prop(ctx, comp_ctx->curr_func.varmap_idx);
66509 } else {
66510 if (varmap_value == -1) {
66511 duk_push_null(ctx);
66512 } else {
66513 DUK_ASSERT(varmap_value >= 0);
66514 duk_push_int(ctx, varmap_value);
66515 }
66516 duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx);
66517 }
66518 /* varname is popped by above code */
66519
66520 DUK_DDD(DUK_DDDPRINT("varmap after restore catch clause: %!iT",
66521 (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx)));
66522
66523 duk__emit_op_only(comp_ctx,
66524 DUK_OP_ENDCATCH);
66525
66526 /*
66527 * XXX: for now, indicate that an expensive catch binding
66528 * declarative environment is always needed. If we don't
66529 * need it, we don't need the const_varname either.
66530 */
66531
66532 trycatch_flags |= DUK_BC_TRYCATCH_FLAG_CATCH_BINDING;
66533
66534 DUK_DDD(DUK_DDDPRINT("stack top at end of catch clause: %ld", (long) duk_get_top(ctx)));
66535 }
66536
66537 if (comp_ctx->curr_token.t == DUK_TOK_FINALLY) {
66538 trycatch_flags |= DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY;
66539
66540 pc_finally = duk__get_current_pc(comp_ctx);
66541
66542 duk__advance(comp_ctx);
66543
66544 duk__advance_expect(comp_ctx, DUK_TOK_LCURLY);
66545 duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
66546 /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
66547 duk__emit_b(comp_ctx,
66548 DUK_OP_ENDFIN,
66549 reg_catch); /* rethrow */
66550 }
66551
66552 if (!(trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) &&
66553 !(trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY)) {
66554 /* must have catch and/or finally */
66555 goto syntax_error;
66556 }
66557
66558 /* If there's no catch block, rc_varname will be 0 and duk__patch_trycatch()
66559 * will replace the LDCONST with a NOP. For any actual constant (including
66560 * constant 0) the DUK__CONST_MARKER flag will be set in rc_varname.
66561 */
66562
66563 duk__patch_trycatch(comp_ctx,
66564 pc_ldconst,
66565 pc_trycatch,
66566 reg_catch,
66567 rc_varname,
66568 trycatch_flags);
66569
66570 if (trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) {
66571 DUK_ASSERT(pc_catch >= 0);
66572 duk__patch_jump(comp_ctx, pc_trycatch + 1, pc_catch);
66573 }
66574
66575 if (trycatch_flags & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY) {
66576 DUK_ASSERT(pc_finally >= 0);
66577 duk__patch_jump(comp_ctx, pc_trycatch + 2, pc_finally);
66578 } else {
66579 /* without finally, the second jump slot is used to jump to end of stmt */
66580 duk__patch_jump_here(comp_ctx, pc_trycatch + 2);
66581 }
66582
66583 comp_ctx->curr_func.catch_depth--;
66584 return;
66585
66586 syntax_error:
66587 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_TRY);
66588}
66589
66590DUK_LOCAL void duk__parse_with_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res) {
66591 duk_int_t pc_trycatch;
66592 duk_int_t pc_finished;
66593 duk_reg_t reg_catch;
66594 duk_small_uint_t trycatch_flags;
66595
66596 if (comp_ctx->curr_func.is_strict) {
66597 DUK_ERROR_SYNTAX(comp_ctx->thr, DUK_STR_WITH_IN_STRICT_MODE);
66598 }
66599
66600 comp_ctx->curr_func.catch_depth++;
66601
66602 duk__advance(comp_ctx); /* eat 'with' */
66603
66604 reg_catch = DUK__ALLOCTEMPS(comp_ctx, 2);
66605
66606 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
66607 duk__exprtop_toforcedreg(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/, reg_catch);
66608 duk__advance_expect(comp_ctx, DUK_TOK_RPAREN);
66609
66610 pc_trycatch = duk__get_current_pc(comp_ctx);
66611 trycatch_flags = DUK_BC_TRYCATCH_FLAG_WITH_BINDING;
66612 duk__emit_a_bc(comp_ctx,
66613 DUK_OP_TRYCATCH | DUK__EMIT_FLAG_NO_SHUFFLE_A,
66614 (duk_regconst_t) trycatch_flags /*a*/,
66615 (duk_regconst_t) reg_catch /*bc*/);
66616 duk__emit_invalid(comp_ctx); /* catch jump */
66617 duk__emit_invalid(comp_ctx); /* finished jump */
66618
66619 duk__parse_stmt(comp_ctx, res, 0 /*allow_source_elem*/);
66620 duk__emit_op_only(comp_ctx,
66621 DUK_OP_ENDTRY);
66622
66623 pc_finished = duk__get_current_pc(comp_ctx);
66624
66625 duk__patch_jump(comp_ctx, pc_trycatch + 2, pc_finished);
66626
66627 comp_ctx->curr_func.catch_depth--;
66628}
66629
66630DUK_LOCAL duk_int_t duk__stmt_label_site(duk_compiler_ctx *comp_ctx, duk_int_t label_id) {
66631 /* if a site already exists, nop: max one label site per statement */
66632 if (label_id >= 0) {
66633 return label_id;
66634 }
66635
66636 label_id = comp_ctx->curr_func.label_next++;
66637 DUK_DDD(DUK_DDDPRINT("allocated new label id for label site: %ld", (long) label_id));
66638
66639 duk__emit_bc(comp_ctx,
66640 DUK_OP_LABEL,
66641 (duk_regconst_t) label_id);
66642 duk__emit_invalid(comp_ctx);
66643 duk__emit_invalid(comp_ctx);
66644
66645 return label_id;
66646}
66647
66648/* Parse a single statement.
66649 *
66650 * Creates a label site (with an empty label) automatically for iteration
66651 * statements. Also "peels off" any label statements for explicit labels.
66652 */
66653DUK_LOCAL void duk__parse_stmt(duk_compiler_ctx *comp_ctx, duk_ivalue *res, duk_bool_t allow_source_elem) {
66654 duk_hthread *thr = comp_ctx->thr;
66655 duk_context *ctx = (duk_context *) thr;
66656 duk_bool_t dir_prol_at_entry; /* directive prologue status at entry */
66657 duk_reg_t temp_at_entry;
66658 duk_uarridx_t labels_len_at_entry;
66659 duk_int_t pc_at_entry; /* assumed to also be PC of "LABEL" */
66660 duk_int_t stmt_id;
66661 duk_small_uint_t stmt_flags = 0;
66662 duk_int_t label_id = -1;
66663 duk_small_uint_t tok;
66664
66665 DUK__RECURSION_INCREASE(comp_ctx, thr);
66666
66667 temp_at_entry = DUK__GETTEMP(comp_ctx);
66668 pc_at_entry = duk__get_current_pc(comp_ctx);
66669 labels_len_at_entry = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.labelnames_idx);
66670 stmt_id = comp_ctx->curr_func.stmt_next++;
66671 dir_prol_at_entry = comp_ctx->curr_func.in_directive_prologue;
66672
66673 DUK_UNREF(stmt_id);
66674
66675 DUK_DDD(DUK_DDDPRINT("parsing a statement, stmt_id=%ld, temp_at_entry=%ld, labels_len_at_entry=%ld, "
66676 "is_strict=%ld, in_directive_prologue=%ld, catch_depth=%ld",
66677 (long) stmt_id, (long) temp_at_entry, (long) labels_len_at_entry,
66678 (long) comp_ctx->curr_func.is_strict, (long) comp_ctx->curr_func.in_directive_prologue,
66679 (long) comp_ctx->curr_func.catch_depth));
66680
66681 /* The directive prologue flag is cleared by default so that it is
66682 * unset for any recursive statement parsing. It is only "revived"
66683 * if a directive is detected. (We could also make directives only
66684 * allowed if 'allow_source_elem' was true.)
66685 */
66686 comp_ctx->curr_func.in_directive_prologue = 0;
66687
66688 retry_parse:
66689
66690 DUK_DDD(DUK_DDDPRINT("try stmt parse, stmt_id=%ld, label_id=%ld, allow_source_elem=%ld, catch_depth=%ld",
66691 (long) stmt_id, (long) label_id, (long) allow_source_elem,
66692 (long) comp_ctx->curr_func.catch_depth));
66693
66694 /*
66695 * Detect iteration statements; if encountered, establish an
66696 * empty label.
66697 */
66698
66699 tok = comp_ctx->curr_token.t;
66700 if (tok == DUK_TOK_FOR || tok == DUK_TOK_DO || tok == DUK_TOK_WHILE ||
66701 tok == DUK_TOK_SWITCH) {
66702 DUK_DDD(DUK_DDDPRINT("iteration/switch statement -> add empty label"));
66703
66704 label_id = duk__stmt_label_site(comp_ctx, label_id);
66705 duk__add_label(comp_ctx,
66706 DUK_HTHREAD_STRING_EMPTY_STRING(thr),
66707 pc_at_entry /*pc_label*/,
66708 label_id);
66709 }
66710
66711 /*
66712 * Main switch for statement / source element type.
66713 */
66714
66715 switch (comp_ctx->curr_token.t) {
66716 case DUK_TOK_FUNCTION: {
66717 /*
66718 * Function declaration, function expression, or (non-standard)
66719 * function statement.
66720 *
66721 * The E5 specification only allows function declarations at
66722 * the top level (in "source elements"). An ExpressionStatement
66723 * is explicitly not allowed to begin with a "function" keyword
66724 * (E5 Section 12.4). Hence any non-error semantics for such
66725 * non-top-level statements are non-standard. Duktape semantics
66726 * for function statements are modelled after V8, see
66727 * test-dev-func-decl-outside-top.js.
66728 */
66729
66730#if defined(DUK_USE_NONSTD_FUNC_STMT)
66731 /* Lenient: allow function declarations outside top level in
66732 * non-strict mode but reject them in strict mode.
66733 */
66734 if (allow_source_elem || !comp_ctx->curr_func.is_strict)
66735#else /* DUK_USE_NONSTD_FUNC_STMT */
66736 /* Strict: never allow function declarations outside top level. */
66737 if (allow_source_elem)
66738#endif /* DUK_USE_NONSTD_FUNC_STMT */
66739 {
66740 /* FunctionDeclaration: not strictly a statement but handled as such.
66741 *
66742 * O(depth^2) parse count for inner functions is handled by recording a
66743 * lexer offset on the first compilation pass, so that the function can
66744 * be efficiently skipped on the second pass. This is encapsulated into
66745 * duk__parse_func_like_fnum().
66746 */
66747
66748 duk_int_t fnum;
66749#if defined(DUK_USE_ASSERTIONS)
66750 duk_idx_t top_before;
66751#endif
66752
66753 DUK_DDD(DUK_DDDPRINT("function declaration statement"));
66754
66755#if defined(DUK_USE_ASSERTIONS)
66756 top_before = duk_get_top(ctx);
66757#endif
66758
66759 duk__advance(comp_ctx); /* eat 'function' */
66760 fnum = duk__parse_func_like_fnum(comp_ctx, DUK__FUNC_FLAG_DECL | DUK__FUNC_FLAG_PUSHNAME_PASS1);
66761
66762 /* The value stack convention here is a bit odd: the function
66763 * name is only pushed on pass 1 (in_scanning), and is needed
66764 * to process function declarations.
66765 */
66766 if (comp_ctx->curr_func.in_scanning) {
66767 duk_uarridx_t n;
66768
66769#if defined(DUK_USE_ASSERTIONS)
66770 DUK_ASSERT(duk_get_top(ctx) == top_before + 1);
66771#endif
66772 DUK_DDD(DUK_DDDPRINT("register function declaration %!T in pass 1, fnum %ld",
66773 duk_get_tval(ctx, -1), (long) fnum));
66774 n = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.decls_idx);
66775 /* funcname is at index -1 */
66776 duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n);
66777 duk_push_int(ctx, (duk_int_t) (DUK_DECL_TYPE_FUNC + (fnum << 8)));
66778 duk_put_prop_index(ctx, comp_ctx->curr_func.decls_idx, n + 1);
66779 } else {
66780#if defined(DUK_USE_ASSERTIONS)
66781 DUK_ASSERT(duk_get_top(ctx) == top_before);
66782#endif
66783 }
66784
66785 /* no statement value (unlike function expression) */
66786 stmt_flags = 0;
66787 break;
66788 } else {
66789 DUK_ERROR_SYNTAX(thr, DUK_STR_FUNC_STMT_NOT_ALLOWED);
66790 }
66791 break;
66792 }
66793 case DUK_TOK_LCURLY: {
66794 DUK_DDD(DUK_DDDPRINT("block statement"));
66795 duk__advance(comp_ctx);
66796 duk__parse_stmts(comp_ctx, 0 /*allow_source_elem*/, 0 /*expect_eof*/);
66797 /* the DUK_TOK_RCURLY is eaten by duk__parse_stmts() */
66798 if (label_id >= 0) {
66799 duk__patch_jump_here(comp_ctx, pc_at_entry + 1); /* break jump */
66800 }
66801 stmt_flags = 0;
66802 break;
66803 }
66804 case DUK_TOK_CONST: {
66805 DUK_DDD(DUK_DDDPRINT("constant declaration statement"));
66806 duk__parse_var_stmt(comp_ctx, res, DUK__EXPR_FLAG_REQUIRE_INIT /*expr_flags*/);
66807 stmt_flags = DUK__HAS_TERM;
66808 break;
66809 }
66810 case DUK_TOK_VAR: {
66811 DUK_DDD(DUK_DDDPRINT("variable declaration statement"));
66812 duk__parse_var_stmt(comp_ctx, res, 0 /*expr_flags*/);
66813 stmt_flags = DUK__HAS_TERM;
66814 break;
66815 }
66816 case DUK_TOK_SEMICOLON: {
66817 /* empty statement with an explicit semicolon */
66818 DUK_DDD(DUK_DDDPRINT("empty statement"));
66819 stmt_flags = DUK__HAS_TERM;
66820 break;
66821 }
66822 case DUK_TOK_IF: {
66823 DUK_DDD(DUK_DDDPRINT("if statement"));
66824 duk__parse_if_stmt(comp_ctx, res);
66825 if (label_id >= 0) {
66826 duk__patch_jump_here(comp_ctx, pc_at_entry + 1); /* break jump */
66827 }
66828 stmt_flags = 0;
66829 break;
66830 }
66831 case DUK_TOK_DO: {
66832 /*
66833 * Do-while statement is mostly trivial, but there is special
66834 * handling for automatic semicolon handling (triggered by the
66835 * DUK__ALLOW_AUTO_SEMI_ALWAYS) flag related to a bug filed at:
66836 *
66837 * https://bugs.ecmascript.org/show_bug.cgi?id=8
66838 *
66839 * See doc/compiler.rst for details.
66840 */
66841 DUK_DDD(DUK_DDDPRINT("do statement"));
66842 DUK_ASSERT(label_id >= 0);
66843 duk__update_label_flags(comp_ctx,
66844 label_id,
66845 DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE);
66846 duk__parse_do_stmt(comp_ctx, res, pc_at_entry);
66847 stmt_flags = DUK__HAS_TERM | DUK__ALLOW_AUTO_SEMI_ALWAYS; /* DUK__ALLOW_AUTO_SEMI_ALWAYS workaround */
66848 break;
66849 }
66850 case DUK_TOK_WHILE: {
66851 DUK_DDD(DUK_DDDPRINT("while statement"));
66852 DUK_ASSERT(label_id >= 0);
66853 duk__update_label_flags(comp_ctx,
66854 label_id,
66855 DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE);
66856 duk__parse_while_stmt(comp_ctx, res, pc_at_entry);
66857 stmt_flags = 0;
66858 break;
66859 }
66860 case DUK_TOK_FOR: {
66861 /*
66862 * For/for-in statement is complicated to parse because
66863 * determining the statement type (three-part for vs. a
66864 * for-in) requires potential backtracking.
66865 *
66866 * See the helper for the messy stuff.
66867 */
66868 DUK_DDD(DUK_DDDPRINT("for/for-in statement"));
66869 DUK_ASSERT(label_id >= 0);
66870 duk__update_label_flags(comp_ctx,
66871 label_id,
66872 DUK_LABEL_FLAG_ALLOW_BREAK | DUK_LABEL_FLAG_ALLOW_CONTINUE);
66873 duk__parse_for_stmt(comp_ctx, res, pc_at_entry);
66874 stmt_flags = 0;
66875 break;
66876 }
66877 case DUK_TOK_CONTINUE:
66878 case DUK_TOK_BREAK: {
66879 DUK_DDD(DUK_DDDPRINT("break/continue statement"));
66880 duk__parse_break_or_continue_stmt(comp_ctx, res);
66881 stmt_flags = DUK__HAS_TERM | DUK__IS_TERMINAL;
66882 break;
66883 }
66884 case DUK_TOK_RETURN: {
66885 DUK_DDD(DUK_DDDPRINT("return statement"));
66886 duk__parse_return_stmt(comp_ctx, res);
66887 stmt_flags = DUK__HAS_TERM | DUK__IS_TERMINAL;
66888 break;
66889 }
66890 case DUK_TOK_WITH: {
66891 DUK_DDD(DUK_DDDPRINT("with statement"));
66892 comp_ctx->curr_func.with_depth++;
66893 duk__parse_with_stmt(comp_ctx, res);
66894 if (label_id >= 0) {
66895 duk__patch_jump_here(comp_ctx, pc_at_entry + 1); /* break jump */
66896 }
66897 comp_ctx->curr_func.with_depth--;
66898 stmt_flags = 0;
66899 break;
66900 }
66901 case DUK_TOK_SWITCH: {
66902 /*
66903 * The switch statement is pretty messy to compile.
66904 * See the helper for details.
66905 */
66906 DUK_DDD(DUK_DDDPRINT("switch statement"));
66907 DUK_ASSERT(label_id >= 0);
66908 duk__update_label_flags(comp_ctx,
66909 label_id,
66910 DUK_LABEL_FLAG_ALLOW_BREAK); /* don't allow continue */
66911 duk__parse_switch_stmt(comp_ctx, res, pc_at_entry);
66912 stmt_flags = 0;
66913 break;
66914 }
66915 case DUK_TOK_THROW: {
66916 DUK_DDD(DUK_DDDPRINT("throw statement"));
66917 duk__parse_throw_stmt(comp_ctx, res);
66918 stmt_flags = DUK__HAS_TERM | DUK__IS_TERMINAL;
66919 break;
66920 }
66921 case DUK_TOK_TRY: {
66922 DUK_DDD(DUK_DDDPRINT("try statement"));
66923 duk__parse_try_stmt(comp_ctx, res);
66924 stmt_flags = 0;
66925 break;
66926 }
66927 case DUK_TOK_DEBUGGER: {
66928 duk__advance(comp_ctx);
66929#if defined(DUK_USE_DEBUGGER_SUPPORT)
66930 DUK_DDD(DUK_DDDPRINT("debugger statement: debugging enabled, emit debugger opcode"));
66931 duk__emit_op_only(comp_ctx, DUK_OP_DEBUGGER);
66932#else
66933 DUK_DDD(DUK_DDDPRINT("debugger statement: ignored"));
66934#endif
66935 stmt_flags = DUK__HAS_TERM;
66936 break;
66937 }
66938 default: {
66939 /*
66940 * Else, must be one of:
66941 * - ExpressionStatement, possibly a directive (String)
66942 * - LabelledStatement (Identifier followed by ':')
66943 *
66944 * Expressions beginning with 'function' keyword are covered by a case
66945 * above (such expressions are not allowed in standard E5 anyway).
66946 * Also expressions starting with '{' are interpreted as block
66947 * statements. See E5 Section 12.4.
66948 *
66949 * Directive detection is tricky; see E5 Section 14.1 on directive
66950 * prologue. A directive is an expression statement with a single
66951 * string literal and an explicit or automatic semicolon. Escape
66952 * characters are significant and no parens etc are allowed:
66953 *
66954 * 'use strict'; // valid 'use strict' directive
66955 * 'use\u0020strict'; // valid directive, not a 'use strict' directive
66956 * ('use strict'); // not a valid directive
66957 *
66958 * The expression is determined to consist of a single string literal
66959 * based on duk__expr_nud() and duk__expr_led() call counts. The string literal
66960 * of a 'use strict' directive is determined to lack any escapes based
66961 * num_escapes count from the lexer. Note that other directives may be
66962 * allowed to contain escapes, so a directive with escapes does not
66963 * terminate a directive prologue.
66964 *
66965 * We rely on the fact that the expression parser will not emit any
66966 * code for a single token expression. However, it will generate an
66967 * intermediate value which we will then successfully ignore.
66968 *
66969 * A similar approach is used for labels.
66970 */
66971
66972 duk_bool_t single_token;
66973
66974 DUK_DDD(DUK_DDDPRINT("expression statement"));
66975 duk__exprtop(comp_ctx, res, DUK__BP_FOR_EXPR /*rbp_flags*/);
66976
66977 single_token = (comp_ctx->curr_func.nud_count == 1 && /* one token */
66978 comp_ctx->curr_func.led_count == 0); /* no operators */
66979
66980 if (single_token &&
66981 comp_ctx->prev_token.t == DUK_TOK_IDENTIFIER &&
66982 comp_ctx->curr_token.t == DUK_TOK_COLON) {
66983 /*
66984 * Detected label
66985 */
66986
66987 duk_hstring *h_lab;
66988
66989 /* expected ival */
66990 DUK_ASSERT(res->t == DUK_IVAL_VAR);
66991 DUK_ASSERT(res->x1.t == DUK_ISPEC_VALUE);
66992 DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(ctx, res->x1.valstack_idx)));
66993 h_lab = comp_ctx->prev_token.str1;
66994 DUK_ASSERT(h_lab != NULL);
66995
66996 DUK_DDD(DUK_DDDPRINT("explicit label site for label '%!O'",
66997 (duk_heaphdr *) h_lab));
66998
66999 duk__advance(comp_ctx); /* eat colon */
67000
67001 label_id = duk__stmt_label_site(comp_ctx, label_id);
67002
67003 duk__add_label(comp_ctx,
67004 h_lab,
67005 pc_at_entry /*pc_label*/,
67006 label_id);
67007
67008 /* a statement following a label cannot be a source element
67009 * (a function declaration).
67010 */
67011 allow_source_elem = 0;
67012
67013 DUK_DDD(DUK_DDDPRINT("label handled, retry statement parsing"));
67014 goto retry_parse;
67015 }
67016
67017 stmt_flags = 0;
67018
67019 if (dir_prol_at_entry && /* still in prologue */
67020 single_token && /* single string token */
67021 comp_ctx->prev_token.t == DUK_TOK_STRING) {
67022 /*
67023 * Detected a directive
67024 */
67025 duk_hstring *h_dir;
67026
67027 /* expected ival */
67028 DUK_ASSERT(res->t == DUK_IVAL_PLAIN);
67029 DUK_ASSERT(res->x1.t == DUK_ISPEC_VALUE);
67030 DUK_ASSERT(DUK_TVAL_IS_STRING(duk_get_tval(ctx, res->x1.valstack_idx)));
67031 h_dir = comp_ctx->prev_token.str1;
67032 DUK_ASSERT(h_dir != NULL);
67033
67034 DUK_DDD(DUK_DDDPRINT("potential directive: %!O", h_dir));
67035
67036 stmt_flags |= DUK__STILL_PROLOGUE;
67037
67038 /* Note: escaped characters differentiate directives */
67039
67040 if (comp_ctx->prev_token.num_escapes > 0) {
67041 DUK_DDD(DUK_DDDPRINT("directive contains escapes: valid directive "
67042 "but we ignore such directives"));
67043 } else {
67044 /*
67045 * The length comparisons are present to handle
67046 * strings like "use strict\u0000foo" as required.
67047 */
67048
67049 if (DUK_HSTRING_GET_BYTELEN(h_dir) == 10 &&
67050 DUK_STRNCMP((const char *) DUK_HSTRING_GET_DATA(h_dir), "use strict", 10) == 0) {
67051#if defined(DUK_USE_STRICT_DECL)
67052 DUK_DDD(DUK_DDDPRINT("use strict directive detected: strict flag %ld -> %ld",
67053 (long) comp_ctx->curr_func.is_strict, (long) 1));
67054 comp_ctx->curr_func.is_strict = 1;
67055#else
67056 DUK_DDD(DUK_DDDPRINT("use strict detected but strict declarations disabled, ignoring"));
67057#endif
67058 } else if (DUK_HSTRING_GET_BYTELEN(h_dir) == 14 &&
67059 DUK_STRNCMP((const char *) DUK_HSTRING_GET_DATA(h_dir), "use duk notail", 14) == 0) {
67060 DUK_DDD(DUK_DDDPRINT("use duk notail directive detected: notail flag %ld -> %ld",
67061 (long) comp_ctx->curr_func.is_notail, (long) 1));
67062 comp_ctx->curr_func.is_notail = 1;
67063 } else {
67064 DUK_DD(DUK_DDPRINT("unknown directive: '%!O', ignoring but not terminating "
67065 "directive prologue", (duk_hobject *) h_dir));
67066 }
67067 }
67068 } else {
67069 DUK_DDD(DUK_DDDPRINT("non-directive expression statement or no longer in prologue; "
67070 "prologue terminated if still active"));
67071 }
67072
67073 stmt_flags |= DUK__HAS_VAL | DUK__HAS_TERM;
67074 }
67075 } /* end switch (tok) */
67076
67077 /*
67078 * Statement value handling.
67079 *
67080 * Global code and eval code has an implicit return value
67081 * which comes from the last statement with a value
67082 * (technically a non-"empty" continuation, which is
67083 * different from an empty statement).
67084 *
67085 * Since we don't know whether a later statement will
67086 * override the value of the current statement, we need
67087 * to coerce the statement value to a register allocated
67088 * for implicit return values. In other cases we need
67089 * to coerce the statement value to a plain value to get
67090 * any side effects out (consider e.g. "foo.bar;").
67091 */
67092
67093 /* XXX: what about statements which leave a half-cooked value in 'res'
67094 * but have no stmt value? Any such statements?
67095 */
67096
67097 if (stmt_flags & DUK__HAS_VAL) {
67098 duk_reg_t reg_stmt_value = comp_ctx->curr_func.reg_stmt_value;
67099 if (reg_stmt_value >= 0) {
67100 duk__ivalue_toforcedreg(comp_ctx, res, reg_stmt_value);
67101 } else {
67102 duk__ivalue_toplain_ignore(comp_ctx, res);
67103 }
67104 } else {
67105 ;
67106 }
67107
67108 /*
67109 * Statement terminator check, including automatic semicolon
67110 * handling. After this step, 'curr_tok' should be the first
67111 * token after a possible statement terminator.
67112 */
67113
67114 if (stmt_flags & DUK__HAS_TERM) {
67115 if (comp_ctx->curr_token.t == DUK_TOK_SEMICOLON) {
67116 DUK_DDD(DUK_DDDPRINT("explicit semicolon terminates statement"));
67117 duk__advance(comp_ctx);
67118 } else {
67119 if (comp_ctx->curr_token.allow_auto_semi) {
67120 DUK_DDD(DUK_DDDPRINT("automatic semicolon terminates statement"));
67121 } else if (stmt_flags & DUK__ALLOW_AUTO_SEMI_ALWAYS) {
67122 /* XXX: make this lenience dependent on flags or strictness? */
67123 DUK_DDD(DUK_DDDPRINT("automatic semicolon terminates statement (allowed for compatibility "
67124 "even though no lineterm present before next token)"));
67125 } else {
67126 DUK_ERROR_SYNTAX(thr, DUK_STR_UNTERMINATED_STMT);
67127 }
67128 }
67129 } else {
67130 DUK_DDD(DUK_DDDPRINT("statement has no terminator"));
67131 }
67132
67133 /*
67134 * Directive prologue tracking.
67135 */
67136
67137 if (stmt_flags & DUK__STILL_PROLOGUE) {
67138 DUK_DDD(DUK_DDDPRINT("setting in_directive_prologue"));
67139 comp_ctx->curr_func.in_directive_prologue = 1;
67140 }
67141
67142 /*
67143 * Cleanups (all statement parsing flows through here).
67144 *
67145 * Pop label site and reset labels. Reset 'next temp' to value at
67146 * entry to reuse temps.
67147 */
67148
67149 if (label_id >= 0) {
67150 duk__emit_bc(comp_ctx,
67151 DUK_OP_ENDLABEL,
67152 (duk_regconst_t) label_id);
67153 }
67154
67155 DUK__SETTEMP(comp_ctx, temp_at_entry);
67156
67157 duk__reset_labels_to_length(comp_ctx, labels_len_at_entry);
67158
67159 /* XXX: return indication of "terminalness" (e.g. a 'throw' is terminal) */
67160
67161 DUK__RECURSION_DECREASE(comp_ctx, thr);
67162}
67163
67164/*
67165 * Parse a statement list.
67166 *
67167 * Handles automatic semicolon insertion and implicit return value.
67168 *
67169 * Upon entry, 'curr_tok' should contain the first token of the first
67170 * statement (parsed in the "allow regexp literal" mode). Upon exit,
67171 * 'curr_tok' contains the token following the statement list terminator
67172 * (EOF or closing brace).
67173 */
67174
67175DUK_LOCAL void duk__parse_stmts(duk_compiler_ctx *comp_ctx, duk_bool_t allow_source_elem, duk_bool_t expect_eof) {
67176 duk_hthread *thr = comp_ctx->thr;
67177 duk_context *ctx = (duk_context *) thr;
67178 duk_ivalue res_alloc;
67179 duk_ivalue *res = &res_alloc;
67180
67181 /* Setup state. Initial ivalue is 'undefined'. */
67182
67183 duk_require_stack(ctx, DUK__PARSE_STATEMENTS_SLOTS);
67184
67185 /* XXX: 'res' setup can be moved to function body level; in fact, two 'res'
67186 * intermediate values suffice for parsing of each function. Nesting is needed
67187 * for nested functions (which may occur inside expressions).
67188 */
67189
67190 DUK_MEMZERO(&res_alloc, sizeof(res_alloc));
67191 res->t = DUK_IVAL_PLAIN;
67192 res->x1.t = DUK_ISPEC_VALUE;
67193 res->x1.valstack_idx = duk_get_top(ctx);
67194 res->x2.valstack_idx = res->x1.valstack_idx + 1;
67195 duk_push_undefined(ctx);
67196 duk_push_undefined(ctx);
67197
67198 /* Parse statements until a closing token (EOF or '}') is found. */
67199
67200 for (;;) {
67201 /* Check whether statement list ends. */
67202
67203 if (expect_eof) {
67204 if (comp_ctx->curr_token.t == DUK_TOK_EOF) {
67205 break;
67206 }
67207 } else {
67208 if (comp_ctx->curr_token.t == DUK_TOK_RCURLY) {
67209 break;
67210 }
67211 }
67212
67213 /* Check statement type based on the first token type.
67214 *
67215 * Note: expression parsing helpers expect 'curr_tok' to
67216 * contain the first token of the expression upon entry.
67217 */
67218
67219 DUK_DDD(DUK_DDDPRINT("TOKEN %ld (non-whitespace, non-comment)", (long) comp_ctx->curr_token.t));
67220
67221 duk__parse_stmt(comp_ctx, res, allow_source_elem);
67222 }
67223
67224 duk__advance(comp_ctx);
67225
67226 /* Tear down state. */
67227
67228 duk_pop_2(ctx);
67229}
67230
67231/*
67232 * Declaration binding instantiation conceptually happens when calling a
67233 * function; for us it essentially means that function prologue. The
67234 * conceptual process is described in E5 Section 10.5.
67235 *
67236 * We need to keep track of all encountered identifiers to (1) create an
67237 * identifier-to-register map ("varmap"); and (2) detect duplicate
67238 * declarations. Identifiers which are not bound to registers still need
67239 * to be tracked for detecting duplicates. Currently such identifiers
67240 * are put into the varmap with a 'null' value, which is later cleaned up.
67241 *
67242 * To support functions with a large number of variable and function
67243 * declarations, registers are not allocated beyond a certain limit;
67244 * after that limit, variables and functions need slow path access.
67245 * Arguments are currently always register bound, which imposes a hard
67246 * (and relatively small) argument count limit.
67247 *
67248 * Some bindings in E5 are not configurable (= deletable) and almost all
67249 * are mutable (writable). Exceptions are:
67250 *
67251 * - The 'arguments' binding, established only if no shadowing argument
67252 * or function declaration exists. We handle 'arguments' creation
67253 * and binding through an explicit slow path environment record.
67254 *
67255 * - The "name" binding for a named function expression. This is also
67256 * handled through an explicit slow path environment record.
67257 */
67258
67259/* XXX: add support for variables to not be register bound always, to
67260 * handle cases with a very large number of variables?
67261 */
67262
67263DUK_LOCAL void duk__init_varmap_and_prologue_for_pass2(duk_compiler_ctx *comp_ctx, duk_reg_t *out_stmt_value_reg) {
67264 duk_hthread *thr = comp_ctx->thr;
67265 duk_context *ctx = (duk_context *) thr;
67266 duk_hstring *h_name;
67267 duk_bool_t configurable_bindings;
67268 duk_uarridx_t num_args;
67269 duk_uarridx_t num_decls;
67270 duk_regconst_t rc_name;
67271 duk_small_uint_t declvar_flags;
67272 duk_uarridx_t i;
67273#if defined(DUK_USE_ASSERTIONS)
67274 duk_idx_t entry_top;
67275#endif
67276
67277#if defined(DUK_USE_ASSERTIONS)
67278 entry_top = duk_get_top(ctx);
67279#endif
67280
67281 /*
67282 * Preliminaries
67283 */
67284
67285 configurable_bindings = comp_ctx->curr_func.is_eval;
67286 DUK_DDD(DUK_DDDPRINT("configurable_bindings=%ld", (long) configurable_bindings));
67287
67288 /* varmap is already in comp_ctx->curr_func.varmap_idx */
67289
67290 /*
67291 * Function formal arguments, always bound to registers
67292 * (there's no support for shuffling them now).
67293 */
67294
67295 num_args = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.argnames_idx);
67296 DUK_DDD(DUK_DDDPRINT("num_args=%ld", (long) num_args));
67297 /* XXX: check num_args */
67298
67299 for (i = 0; i < num_args; i++) {
67300 duk_get_prop_index(ctx, comp_ctx->curr_func.argnames_idx, i);
67301 h_name = duk_known_hstring(ctx, -1);
67302
67303 if (comp_ctx->curr_func.is_strict) {
67304 if (duk__hstring_is_eval_or_arguments(comp_ctx, h_name)) {
67305 DUK_DDD(DUK_DDDPRINT("arg named 'eval' or 'arguments' in strict mode -> SyntaxError"));
67306 goto error_argname;
67307 }
67308 duk_dup_top(ctx);
67309 if (duk_has_prop(ctx, comp_ctx->curr_func.varmap_idx)) {
67310 DUK_DDD(DUK_DDDPRINT("duplicate arg name in strict mode -> SyntaxError"));
67311 goto error_argname;
67312 }
67313
67314 /* Ensure argument name is not a reserved word in current
67315 * (final) strictness. Formal argument parsing may not
67316 * catch reserved names if strictness changes during
67317 * parsing.
67318 *
67319 * We only need to do this in strict mode because non-strict
67320 * keyword are always detected in formal argument parsing.
67321 */
67322
67323 if (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(h_name)) {
67324 goto error_argname;
67325 }
67326 }
67327
67328 /* overwrite any previous binding of the same name; the effect is
67329 * that last argument of a certain name wins.
67330 */
67331
67332 /* only functions can have arguments */
67333 DUK_ASSERT(comp_ctx->curr_func.is_function);
67334 duk_push_uarridx(ctx, i); /* -> [ ... name index ] */
67335 duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx); /* -> [ ... ] */
67336
67337 /* no code needs to be emitted, the regs already have values */
67338 }
67339
67340 /* use temp_next for tracking register allocations */
67341 DUK__SETTEMP_CHECKMAX(comp_ctx, (duk_reg_t) num_args);
67342
67343 /*
67344 * After arguments, allocate special registers (like shuffling temps)
67345 */
67346
67347 if (out_stmt_value_reg) {
67348 *out_stmt_value_reg = DUK__ALLOCTEMP(comp_ctx);
67349 }
67350 if (comp_ctx->curr_func.needs_shuffle) {
67351 duk_reg_t shuffle_base = DUK__ALLOCTEMPS(comp_ctx, 3);
67352 comp_ctx->curr_func.shuffle1 = shuffle_base;
67353 comp_ctx->curr_func.shuffle2 = shuffle_base + 1;
67354 comp_ctx->curr_func.shuffle3 = shuffle_base + 2;
67355 DUK_D(DUK_DPRINT("shuffle registers needed by function, allocated: %ld %ld %ld",
67356 (long) comp_ctx->curr_func.shuffle1,
67357 (long) comp_ctx->curr_func.shuffle2,
67358 (long) comp_ctx->curr_func.shuffle3));
67359 }
67360 if (comp_ctx->curr_func.temp_next > 0x100) {
67361 DUK_D(DUK_DPRINT("not enough 8-bit regs: temp_next=%ld", (long) comp_ctx->curr_func.temp_next));
67362 goto error_outofregs;
67363 }
67364
67365 /*
67366 * Function declarations
67367 */
67368
67369 num_decls = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.decls_idx);
67370 DUK_DDD(DUK_DDDPRINT("num_decls=%ld -> %!T",
67371 (long) num_decls,
67372 (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.decls_idx)));
67373 for (i = 0; i < num_decls; i += 2) {
67374 duk_int_t decl_type;
67375 duk_int_t fnum;
67376
67377 duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i + 1); /* decl type */
67378 decl_type = duk_to_int(ctx, -1);
67379 fnum = decl_type >> 8; /* XXX: macros */
67380 decl_type = decl_type & 0xff;
67381 duk_pop(ctx);
67382
67383 if (decl_type != DUK_DECL_TYPE_FUNC) {
67384 continue;
67385 }
67386
67387 duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i); /* decl name */
67388
67389 /* XXX: spilling */
67390 if (comp_ctx->curr_func.is_function) {
67391 duk_reg_t reg_bind;
67392 duk_dup_top(ctx);
67393 if (duk_has_prop(ctx, comp_ctx->curr_func.varmap_idx)) {
67394 /* shadowed; update value */
67395 duk_dup_top(ctx);
67396 duk_get_prop(ctx, comp_ctx->curr_func.varmap_idx);
67397 reg_bind = duk_to_int(ctx, -1); /* [ ... name reg_bind ] */
67398 duk__emit_a_bc(comp_ctx,
67399 DUK_OP_CLOSURE,
67400 (duk_regconst_t) reg_bind,
67401 (duk_regconst_t) fnum);
67402 } else {
67403 /* function: always register bound */
67404 reg_bind = DUK__ALLOCTEMP(comp_ctx);
67405 duk__emit_a_bc(comp_ctx,
67406 DUK_OP_CLOSURE,
67407 (duk_regconst_t) reg_bind,
67408 (duk_regconst_t) fnum);
67409 duk_push_int(ctx, (duk_int_t) reg_bind);
67410 }
67411 } else {
67412 /* Function declaration for global/eval code is emitted even
67413 * for duplicates, because of E5 Section 10.5, step 5.e of
67414 * E5.1 (special behavior for variable bound to global object).
67415 *
67416 * DECLVAR will not re-declare a variable as such, but will
67417 * update the binding value.
67418 */
67419
67420 duk_reg_t reg_temp = DUK__ALLOCTEMP(comp_ctx);
67421 duk_dup_top(ctx);
67422 rc_name = duk__getconst(comp_ctx);
67423 duk_push_null(ctx);
67424
67425 duk__emit_a_bc(comp_ctx,
67426 DUK_OP_CLOSURE,
67427 (duk_regconst_t) reg_temp,
67428 (duk_regconst_t) fnum);
67429
67430 declvar_flags = DUK_PROPDESC_FLAG_WRITABLE |
67431 DUK_PROPDESC_FLAG_ENUMERABLE |
67432 DUK_BC_DECLVAR_FLAG_FUNC_DECL;
67433
67434 if (configurable_bindings) {
67435 declvar_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
67436 }
67437
67438 duk__emit_a_b_c(comp_ctx,
67439 DUK_OP_DECLVAR | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_BC_REGCONST,
67440 (duk_regconst_t) declvar_flags /*flags*/,
67441 rc_name /*name*/,
67442 (duk_regconst_t) reg_temp /*value*/);
67443
67444 DUK__SETTEMP(comp_ctx, reg_temp); /* forget temp */
67445 }
67446
67447 DUK_DDD(DUK_DDDPRINT("function declaration to varmap: %!T -> %!T",
67448 (duk_tval *) duk_get_tval(ctx, -2),
67449 (duk_tval *) duk_get_tval(ctx, -1)));
67450
67451 duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */
67452 }
67453
67454 /*
67455 * 'arguments' binding is special; if a shadowing argument or
67456 * function declaration exists, an arguments object will
67457 * definitely not be needed, regardless of whether the identifier
67458 * 'arguments' is referenced inside the function body.
67459 */
67460
67461 if (duk_has_prop_stridx(ctx, comp_ctx->curr_func.varmap_idx, DUK_STRIDX_LC_ARGUMENTS)) {
67462 DUK_DDD(DUK_DDDPRINT("'arguments' is shadowed by argument or function declaration "
67463 "-> arguments object creation can be skipped"));
67464 comp_ctx->curr_func.is_arguments_shadowed = 1;
67465 }
67466
67467 /*
67468 * Variable declarations.
67469 *
67470 * Unlike function declarations, variable declaration values don't get
67471 * assigned on entry. If a binding of the same name already exists, just
67472 * ignore it silently.
67473 */
67474
67475 for (i = 0; i < num_decls; i += 2) {
67476 duk_int_t decl_type;
67477
67478 duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i + 1); /* decl type */
67479 decl_type = duk_to_int(ctx, -1);
67480 decl_type = decl_type & 0xff;
67481 duk_pop(ctx);
67482
67483 if (decl_type != DUK_DECL_TYPE_VAR) {
67484 continue;
67485 }
67486
67487 duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i); /* decl name */
67488
67489 if (duk_has_prop(ctx, comp_ctx->curr_func.varmap_idx)) {
67490 /* shadowed, ignore */
67491 } else {
67492 duk_get_prop_index(ctx, comp_ctx->curr_func.decls_idx, i); /* decl name */
67493 h_name = duk_known_hstring(ctx, -1);
67494
67495 if (h_name == DUK_HTHREAD_STRING_LC_ARGUMENTS(thr) &&
67496 !comp_ctx->curr_func.is_arguments_shadowed) {
67497 /* E5 Section steps 7-8 */
67498 DUK_DDD(DUK_DDDPRINT("'arguments' not shadowed by a function declaration, "
67499 "but appears as a variable declaration -> treat as "
67500 "a no-op for variable declaration purposes"));
67501 duk_pop(ctx);
67502 continue;
67503 }
67504
67505 /* XXX: spilling */
67506 if (comp_ctx->curr_func.is_function) {
67507 duk_reg_t reg_bind = DUK__ALLOCTEMP(comp_ctx);
67508 /* no need to init reg, it will be undefined on entry */
67509 duk_push_int(ctx, (duk_int_t) reg_bind);
67510 } else {
67511 duk_dup_top(ctx);
67512 rc_name = duk__getconst(comp_ctx);
67513 duk_push_null(ctx);
67514
67515 declvar_flags = DUK_PROPDESC_FLAG_WRITABLE |
67516 DUK_PROPDESC_FLAG_ENUMERABLE |
67517 DUK_BC_DECLVAR_FLAG_UNDEF_VALUE;
67518 if (configurable_bindings) {
67519 declvar_flags |= DUK_PROPDESC_FLAG_CONFIGURABLE;
67520 }
67521
67522 duk__emit_a_b_c(comp_ctx,
67523 DUK_OP_DECLVAR | DUK__EMIT_FLAG_NO_SHUFFLE_A | DUK__EMIT_FLAG_BC_REGCONST,
67524 (duk_regconst_t) declvar_flags /*flags*/,
67525 rc_name /*name*/,
67526 (duk_regconst_t) 0 /*value*/);
67527 }
67528
67529 duk_put_prop(ctx, comp_ctx->curr_func.varmap_idx); /* [ ... name reg/null ] -> [ ... ] */
67530 }
67531 }
67532
67533 /*
67534 * Wrap up
67535 */
67536
67537 DUK_DDD(DUK_DDDPRINT("varmap: %!T, is_arguments_shadowed=%ld",
67538 (duk_tval *) duk_get_tval(ctx, comp_ctx->curr_func.varmap_idx),
67539 (long) comp_ctx->curr_func.is_arguments_shadowed));
67540
67541 DUK_ASSERT_TOP(ctx, entry_top);
67542 return;
67543
67544 error_outofregs:
67545 DUK_ERROR_RANGE(thr, DUK_STR_REG_LIMIT);
67546 DUK_UNREACHABLE();
67547 return;
67548
67549 error_argname:
67550 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_ARG_NAME);
67551 DUK_UNREACHABLE();
67552 return;
67553}
67554
67555/*
67556 * Parse a function-body-like expression (FunctionBody or Program
67557 * in E5 grammar) using a two-pass parse. The productions appear
67558 * in the following contexts:
67559 *
67560 * - function expression
67561 * - function statement
67562 * - function declaration
67563 * - getter in object literal
67564 * - setter in object literal
67565 * - global code
67566 * - eval code
67567 * - Function constructor body
67568 *
67569 * This function only parses the statement list of the body; the argument
67570 * list and possible function name must be initialized by the caller.
67571 * For instance, for Function constructor, the argument names are originally
67572 * on the value stack. The parsing of statements ends either at an EOF or
67573 * a closing brace; this is controlled by an input flag.
67574 *
67575 * Note that there are many differences affecting parsing and even code
67576 * generation:
67577 *
67578 * - Global and eval code have an implicit return value generated
67579 * by the last statement; function code does not
67580 *
67581 * - Global code, eval code, and Function constructor body end in
67582 * an EOF, other bodies in a closing brace ('}')
67583 *
67584 * Upon entry, 'curr_tok' is ignored and the function will pull in the
67585 * first token on its own. Upon exit, 'curr_tok' is the terminating
67586 * token (EOF or closing brace).
67587 */
67588
67589DUK_LOCAL void duk__parse_func_body(duk_compiler_ctx *comp_ctx, duk_bool_t expect_eof, duk_bool_t implicit_return_value, duk_small_int_t expect_token) {
67590 duk_compiler_func *func;
67591 duk_hthread *thr;
67592 duk_context *ctx;
67593 duk_reg_t reg_stmt_value = -1;
67594 duk_lexer_point lex_pt;
67595 duk_reg_t temp_first;
67596 duk_small_int_t compile_round = 1;
67597
67598 DUK_ASSERT(comp_ctx != NULL);
67599
67600 thr = comp_ctx->thr;
67601 ctx = (duk_context *) thr;
67602 DUK_ASSERT(thr != NULL);
67603
67604 func = &comp_ctx->curr_func;
67605 DUK_ASSERT(func != NULL);
67606
67607 DUK__RECURSION_INCREASE(comp_ctx, thr);
67608
67609 duk_require_stack(ctx, DUK__FUNCTION_BODY_REQUIRE_SLOTS);
67610
67611 /*
67612 * Store lexer position for a later rewind
67613 */
67614
67615 DUK_LEXER_GETPOINT(&comp_ctx->lex, &lex_pt);
67616
67617 /*
67618 * Program code (global and eval code) has an implicit return value
67619 * from the last statement value (e.g. eval("1; 2+3;") returns 3).
67620 * This is not the case with functions. If implicit statement return
67621 * value is requested, all statements are coerced to a register
67622 * allocated here, and used in the implicit return statement below.
67623 */
67624
67625 /* XXX: this is pointless here because pass 1 is throw-away */
67626 if (implicit_return_value) {
67627 reg_stmt_value = DUK__ALLOCTEMP(comp_ctx);
67628
67629 /* If an implicit return value is needed by caller, it must be
67630 * initialized to 'undefined' because we don't know whether any
67631 * non-empty (where "empty" is a continuation type, and different
67632 * from an empty statement) statements will be executed.
67633 *
67634 * However, since 1st pass is a throwaway one, no need to emit
67635 * it here.
67636 */
67637#if 0
67638 duk__emit_bc(comp_ctx,
67639 DUK_OP_LDUNDEF,
67640 0);
67641#endif
67642 }
67643
67644 /*
67645 * First pass.
67646 *
67647 * Gather variable/function declarations needed for second pass.
67648 * Code generated is dummy and discarded.
67649 */
67650
67651 func->in_directive_prologue = 1;
67652 func->in_scanning = 1;
67653 func->may_direct_eval = 0;
67654 func->id_access_arguments = 0;
67655 func->id_access_slow = 0;
67656 func->id_access_slow_own = 0;
67657 func->reg_stmt_value = reg_stmt_value;
67658#if defined(DUK_USE_DEBUGGER_SUPPORT)
67659 func->min_line = DUK_INT_MAX;
67660 func->max_line = 0;
67661#endif
67662
67663 /* duk__parse_stmts() expects curr_tok to be set; parse in "allow regexp literal" mode with current strictness */
67664 if (expect_token >= 0) {
67665 /* Eating a left curly; regexp mode is allowed by left curly
67666 * based on duk__token_lbp[] automatically.
67667 */
67668 DUK_ASSERT(expect_token == DUK_TOK_LCURLY);
67669 duk__update_lineinfo_currtoken(comp_ctx);
67670 duk__advance_expect(comp_ctx, expect_token);
67671 } else {
67672 /* Need to set curr_token.t because lexing regexp mode depends on current
67673 * token type. Zero value causes "allow regexp" mode.
67674 */
67675 comp_ctx->curr_token.t = 0;
67676 duk__advance(comp_ctx);
67677 }
67678
67679 DUK_DDD(DUK_DDDPRINT("begin 1st pass"));
67680 duk__parse_stmts(comp_ctx,
67681 1, /* allow source elements */
67682 expect_eof); /* expect EOF instead of } */
67683 DUK_DDD(DUK_DDDPRINT("end 1st pass"));
67684
67685 /*
67686 * Second (and possibly third) pass.
67687 *
67688 * Generate actual code. In most cases the need for shuffle
67689 * registers is detected during pass 1, but in some corner cases
67690 * we'll only detect it during pass 2 and a third pass is then
67691 * needed (see GH-115).
67692 */
67693
67694 for (;;) {
67695 duk_bool_t needs_shuffle_before = comp_ctx->curr_func.needs_shuffle;
67696 compile_round++;
67697
67698 /*
67699 * Rewind lexer.
67700 *
67701 * duk__parse_stmts() expects curr_tok to be set; parse in "allow regexp
67702 * literal" mode with current strictness.
67703 *
67704 * curr_token line number info should be initialized for pass 2 before
67705 * generating prologue, to ensure prologue bytecode gets nice line numbers.
67706 */
67707
67708 DUK_DDD(DUK_DDDPRINT("rewind lexer"));
67709 DUK_LEXER_SETPOINT(&comp_ctx->lex, &lex_pt);
67710 comp_ctx->curr_token.t = 0; /* this is needed for regexp mode */
67711 comp_ctx->curr_token.start_line = 0; /* needed for line number tracking (becomes prev_token.start_line) */
67712 duk__advance(comp_ctx);
67713
67714 /*
67715 * Reset function state and perform register allocation, which creates
67716 * 'varmap' for second pass. Function prologue for variable declarations,
67717 * binding value initializations etc is emitted as a by-product.
67718 *
67719 * Strict mode restrictions for duplicate and invalid argument
67720 * names are checked here now that we know whether the function
67721 * is actually strict. See: test-dev-strict-mode-boundary.js.
67722 *
67723 * Inner functions are compiled during pass 1 and are not reset.
67724 */
67725
67726 duk__reset_func_for_pass2(comp_ctx);
67727 func->in_directive_prologue = 1;
67728 func->in_scanning = 0;
67729
67730 /* must be able to emit code, alloc consts, etc. */
67731
67732 duk__init_varmap_and_prologue_for_pass2(comp_ctx,
67733 (implicit_return_value ? &reg_stmt_value : NULL));
67734 func->reg_stmt_value = reg_stmt_value;
67735
67736 temp_first = DUK__GETTEMP(comp_ctx);
67737
67738 func->temp_first = temp_first;
67739 func->temp_next = temp_first;
67740 func->stmt_next = 0;
67741 func->label_next = 0;
67742
67743 /* XXX: init or assert catch depth etc -- all values */
67744 func->id_access_arguments = 0;
67745 func->id_access_slow = 0;
67746 func->id_access_slow_own = 0;
67747
67748 /*
67749 * Check function name validity now that we know strictness.
67750 * This only applies to function declarations and expressions,
67751 * not setter/getter name.
67752 *
67753 * See: test-dev-strict-mode-boundary.js
67754 */
67755
67756 if (func->is_function && !func->is_setget && func->h_name != NULL) {
67757 if (func->is_strict) {
67758 if (duk__hstring_is_eval_or_arguments(comp_ctx, func->h_name)) {
67759 DUK_DDD(DUK_DDDPRINT("func name is 'eval' or 'arguments' in strict mode"));
67760 goto error_funcname;
67761 }
67762 if (DUK_HSTRING_HAS_STRICT_RESERVED_WORD(func->h_name)) {
67763 DUK_DDD(DUK_DDDPRINT("func name is a reserved word in strict mode"));
67764 goto error_funcname;
67765 }
67766 } else {
67767 if (DUK_HSTRING_HAS_RESERVED_WORD(func->h_name) &&
67768 !DUK_HSTRING_HAS_STRICT_RESERVED_WORD(func->h_name)) {
67769 DUK_DDD(DUK_DDDPRINT("func name is a reserved word in non-strict mode"));
67770 goto error_funcname;
67771 }
67772 }
67773 }
67774
67775 /*
67776 * Second pass parsing.
67777 */
67778
67779 if (implicit_return_value) {
67780 /* Default implicit return value. */
67781 duk__emit_bc(comp_ctx,
67782 DUK_OP_LDUNDEF,
67783 0);
67784 }
67785
67786 DUK_DDD(DUK_DDDPRINT("begin 2nd pass"));
67787 duk__parse_stmts(comp_ctx,
67788 1, /* allow source elements */
67789 expect_eof); /* expect EOF instead of } */
67790 DUK_DDD(DUK_DDDPRINT("end 2nd pass"));
67791
67792 duk__update_lineinfo_currtoken(comp_ctx);
67793
67794 if (needs_shuffle_before == comp_ctx->curr_func.needs_shuffle) {
67795 /* Shuffle decision not changed. */
67796 break;
67797 }
67798 if (compile_round >= 3) {
67799 /* Should never happen but avoid infinite loop just in case. */
67800 DUK_D(DUK_DPRINT("more than 3 compile passes needed, should never happen"));
67801 DUK_ERROR_INTERNAL(thr);
67802 }
67803 DUK_D(DUK_DPRINT("need additional round to compile function, round now %d", (int) compile_round));
67804 }
67805
67806 /*
67807 * Emit a final RETURN.
67808 *
67809 * It would be nice to avoid emitting an unnecessary "return" opcode
67810 * if the current PC is not reachable. However, this cannot be reliably
67811 * detected; even if the previous instruction is an unconditional jump,
67812 * there may be a previous jump which jumps to current PC (which is the
67813 * case for iteration and conditional statements, for instance).
67814 */
67815
67816 /* XXX: request a "last statement is terminal" from duk__parse_stmt() and duk__parse_stmts();
67817 * we could avoid the last RETURN if we could ensure there is no way to get here
67818 * (directly or via a jump)
67819 */
67820
67821 DUK_ASSERT(comp_ctx->curr_func.catch_depth == 0);
67822 if (reg_stmt_value >= 0) {
67823 DUK_ASSERT(DUK__ISREG(reg_stmt_value));
67824 duk__emit_bc(comp_ctx, DUK_OP_RETREG, (duk_regconst_t) reg_stmt_value /*reg*/);
67825 } else {
67826 duk__emit_op_only(comp_ctx, DUK_OP_RETUNDEF);
67827 }
67828
67829 /*
67830 * Peephole optimize JUMP chains.
67831 */
67832
67833 duk__peephole_optimize_bytecode(comp_ctx);
67834
67835 /*
67836 * comp_ctx->curr_func is now ready to be converted into an actual
67837 * function template.
67838 */
67839
67840 DUK__RECURSION_DECREASE(comp_ctx, thr);
67841 return;
67842
67843 error_funcname:
67844 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_FUNC_NAME);
67845}
67846
67847/*
67848 * Parse a function-like expression:
67849 *
67850 * - function expression
67851 * - function declaration
67852 * - function statement (non-standard)
67853 * - setter/getter
67854 *
67855 * Adds the function to comp_ctx->curr_func function table and returns the
67856 * function number.
67857 *
67858 * On entry, curr_token points to:
67859 *
67860 * - the token after 'function' for function expression/declaration/statement
67861 * - the token after 'set' or 'get' for setter/getter
67862 */
67863
67864/* Parse formals. */
67865DUK_LOCAL void duk__parse_func_formals(duk_compiler_ctx *comp_ctx) {
67866 duk_hthread *thr = comp_ctx->thr;
67867 duk_context *ctx = (duk_context *) thr;
67868 duk_bool_t first = 1;
67869 duk_uarridx_t n;
67870
67871 for (;;) {
67872 if (comp_ctx->curr_token.t == DUK_TOK_RPAREN) {
67873 break;
67874 }
67875
67876 if (first) {
67877 /* no comma */
67878 first = 0;
67879 } else {
67880 duk__advance_expect(comp_ctx, DUK_TOK_COMMA);
67881 }
67882
67883 /* Note: when parsing a formal list in non-strict context, e.g.
67884 * "implements" is parsed as an identifier. When the function is
67885 * later detected to be strict, the argument list must be rechecked
67886 * against a larger set of reserved words (that of strict mode).
67887 * This is handled by duk__parse_func_body(). Here we recognize
67888 * whatever tokens are considered reserved in current strictness
67889 * (which is not always enough).
67890 */
67891
67892 if (comp_ctx->curr_token.t != DUK_TOK_IDENTIFIER) {
67893 DUK_ERROR_SYNTAX(thr, "expected identifier");
67894 }
67895 DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_IDENTIFIER);
67896 DUK_ASSERT(comp_ctx->curr_token.str1 != NULL);
67897 DUK_DDD(DUK_DDDPRINT("formal argument: %!O",
67898 (duk_heaphdr *) comp_ctx->curr_token.str1));
67899
67900 /* XXX: append primitive */
67901 duk_push_hstring(ctx, comp_ctx->curr_token.str1);
67902 n = (duk_uarridx_t) duk_get_length(ctx, comp_ctx->curr_func.argnames_idx);
67903 duk_put_prop_index(ctx, comp_ctx->curr_func.argnames_idx, n);
67904
67905 duk__advance(comp_ctx); /* eat identifier */
67906 }
67907}
67908
67909/* Parse a function-like expression, assuming that 'comp_ctx->curr_func' is
67910 * correctly set up. Assumes that curr_token is just after 'function' (or
67911 * 'set'/'get' etc).
67912 */
67913DUK_LOCAL void duk__parse_func_like_raw(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags) {
67914 duk_hthread *thr = comp_ctx->thr;
67915 duk_context *ctx = (duk_context *) thr;
67916 duk_token *tok;
67917 duk_bool_t no_advance;
67918
67919 DUK_ASSERT(comp_ctx->curr_func.num_formals == 0);
67920 DUK_ASSERT(comp_ctx->curr_func.is_function == 1);
67921 DUK_ASSERT(comp_ctx->curr_func.is_eval == 0);
67922 DUK_ASSERT(comp_ctx->curr_func.is_global == 0);
67923 DUK_ASSERT(comp_ctx->curr_func.is_setget == ((flags & DUK__FUNC_FLAG_GETSET) != 0));
67924
67925 duk__update_lineinfo_currtoken(comp_ctx);
67926
67927 /*
67928 * Function name (if any)
67929 *
67930 * We don't check for prohibited names here, because we don't
67931 * yet know whether the function will be strict. Function body
67932 * parsing handles this retroactively.
67933 *
67934 * For function expressions and declarations function name must
67935 * be an Identifer (excludes reserved words). For setter/getter
67936 * it is a PropertyName which allows reserved words and also
67937 * strings and numbers (e.g. "{ get 1() { ... } }").
67938 *
67939 * Function parsing may start either from prev_token or curr_token
67940 * (object literal method definition uses prev_token for example).
67941 * This is dealt with for the initial token.
67942 */
67943
67944 no_advance = (flags & DUK__FUNC_FLAG_USE_PREVTOKEN);
67945 if (no_advance) {
67946 tok = &comp_ctx->prev_token;
67947 } else {
67948 tok = &comp_ctx->curr_token;
67949 }
67950
67951 if (flags & DUK__FUNC_FLAG_GETSET) {
67952 /* PropertyName -> IdentifierName | StringLiteral | NumericLiteral */
67953 if (tok->t_nores == DUK_TOK_IDENTIFIER || tok->t == DUK_TOK_STRING) {
67954 duk_push_hstring(ctx, tok->str1); /* keep in valstack */
67955 } else if (tok->t == DUK_TOK_NUMBER) {
67956 duk_push_number(ctx, tok->num);
67957 duk_to_string(ctx, -1);
67958 } else {
67959 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_GETSET_NAME);
67960 }
67961 comp_ctx->curr_func.h_name = duk_known_hstring(ctx, -1); /* borrowed reference */
67962 } else {
67963 /* Function name is an Identifier (not IdentifierName), but we get
67964 * the raw name (not recognizing keywords) here and perform the name
67965 * checks only after pass 1.
67966 */
67967 if (tok->t_nores == DUK_TOK_IDENTIFIER) {
67968 duk_push_hstring(ctx, tok->str1); /* keep in valstack */
67969 comp_ctx->curr_func.h_name = duk_known_hstring(ctx, -1); /* borrowed reference */
67970 } else {
67971 /* valstack will be unbalanced, which is OK */
67972 DUK_ASSERT((flags & DUK__FUNC_FLAG_GETSET) == 0);
67973 DUK_ASSERT(comp_ctx->curr_func.h_name == NULL);
67974 no_advance = 1;
67975 if (flags & DUK__FUNC_FLAG_DECL) {
67976 DUK_ERROR_SYNTAX(thr, DUK_STR_FUNC_NAME_REQUIRED);
67977 }
67978 }
67979 }
67980
67981 DUK_DD(DUK_DDPRINT("function name: %!O",
67982 (duk_heaphdr *) comp_ctx->curr_func.h_name));
67983
67984 if (!no_advance) {
67985 duk__advance(comp_ctx);
67986 }
67987
67988 /*
67989 * Formal argument list
67990 *
67991 * We don't check for prohibited names or for duplicate argument
67992 * names here, becase we don't yet know whether the function will
67993 * be strict. Function body parsing handles this retroactively.
67994 */
67995
67996 duk__advance_expect(comp_ctx, DUK_TOK_LPAREN);
67997
67998 duk__parse_func_formals(comp_ctx);
67999
68000 DUK_ASSERT(comp_ctx->curr_token.t == DUK_TOK_RPAREN);
68001 duk__advance(comp_ctx);
68002
68003 /*
68004 * Parse function body
68005 */
68006
68007 duk__parse_func_body(comp_ctx,
68008 0, /* expect_eof */
68009 0, /* implicit_return_value */
68010 DUK_TOK_LCURLY); /* expect_token */
68011
68012 /*
68013 * Convert duk_compiler_func to a function template and add it
68014 * to the parent function table.
68015 */
68016
68017 duk__convert_to_func_template(comp_ctx); /* -> [ ... func ] */
68018}
68019
68020/* Parse an inner function, adding the function template to the current function's
68021 * function table. Return a function number to be used by the outer function.
68022 *
68023 * Avoiding O(depth^2) inner function parsing is handled here. On the first pass,
68024 * compile and register the function normally into the 'funcs' array, also recording
68025 * a lexer point (offset/line) to the closing brace of the function. On the second
68026 * pass, skip the function and return the same 'fnum' as on the first pass by using
68027 * a running counter.
68028 *
68029 * An unfortunate side effect of this is that when parsing the inner function, almost
68030 * nothing is known of the outer function, i.e. the inner function's scope. We don't
68031 * need that information at the moment, but it would allow some optimizations if it
68032 * were used.
68033 */
68034DUK_LOCAL duk_int_t duk__parse_func_like_fnum(duk_compiler_ctx *comp_ctx, duk_small_uint_t flags) {
68035 duk_hthread *thr = comp_ctx->thr;
68036 duk_context *ctx = (duk_context *) thr;
68037 duk_compiler_func old_func;
68038 duk_idx_t entry_top;
68039 duk_int_t fnum;
68040
68041 /*
68042 * On second pass, skip the function.
68043 */
68044
68045 if (!comp_ctx->curr_func.in_scanning) {
68046 duk_lexer_point lex_pt;
68047
68048 fnum = comp_ctx->curr_func.fnum_next++;
68049 duk_get_prop_index(ctx, comp_ctx->curr_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 1));
68050 lex_pt.offset = duk_to_int(ctx, -1);
68051 duk_pop(ctx);
68052 duk_get_prop_index(ctx, comp_ctx->curr_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 2));
68053 lex_pt.line = duk_to_int(ctx, -1);
68054 duk_pop(ctx);
68055
68056 DUK_DDD(DUK_DDDPRINT("second pass of an inner func, skip the function, reparse closing brace; lex offset=%ld, line=%ld",
68057 (long) lex_pt.offset, (long) lex_pt.line));
68058
68059 DUK_LEXER_SETPOINT(&comp_ctx->lex, &lex_pt);
68060 comp_ctx->curr_token.t = 0; /* this is needed for regexp mode */
68061 comp_ctx->curr_token.start_line = 0; /* needed for line number tracking (becomes prev_token.start_line) */
68062 duk__advance(comp_ctx);
68063 duk__advance_expect(comp_ctx, DUK_TOK_RCURLY);
68064
68065 return fnum;
68066 }
68067
68068 /*
68069 * On first pass, perform actual parsing. Remember valstack top on entry
68070 * to restore it later, and switch to using a new function in comp_ctx.
68071 */
68072
68073 entry_top = duk_get_top(ctx);
68074 DUK_DDD(DUK_DDDPRINT("before func: entry_top=%ld, curr_tok.start_offset=%ld",
68075 (long) entry_top, (long) comp_ctx->curr_token.start_offset));
68076
68077 DUK_MEMCPY(&old_func, &comp_ctx->curr_func, sizeof(duk_compiler_func));
68078
68079 DUK_MEMZERO(&comp_ctx->curr_func, sizeof(duk_compiler_func));
68080 duk__init_func_valstack_slots(comp_ctx);
68081 DUK_ASSERT(comp_ctx->curr_func.num_formals == 0);
68082
68083 /* inherit initial strictness from parent */
68084 comp_ctx->curr_func.is_strict = old_func.is_strict;
68085
68086 /* XXX: It might be better to just store the flags into the curr_func
68087 * struct and use them as is without this flag interpretation step
68088 * here.
68089 */
68090 DUK_ASSERT(comp_ctx->curr_func.is_notail == 0);
68091 comp_ctx->curr_func.is_function = 1;
68092 DUK_ASSERT(comp_ctx->curr_func.is_eval == 0);
68093 DUK_ASSERT(comp_ctx->curr_func.is_global == 0);
68094 comp_ctx->curr_func.is_setget = ((flags & DUK__FUNC_FLAG_GETSET) != 0);
68095 comp_ctx->curr_func.is_namebinding = !(flags & (DUK__FUNC_FLAG_GETSET |
68096 DUK__FUNC_FLAG_METDEF |
68097 DUK__FUNC_FLAG_DECL)); /* no name binding for: declarations, objlit getset, objlit method def */
68098 comp_ctx->curr_func.is_constructable = !(flags & (DUK__FUNC_FLAG_GETSET |
68099 DUK__FUNC_FLAG_METDEF)); /* not constructable: objlit getset, objlit method def */
68100
68101 /*
68102 * Parse inner function
68103 */
68104
68105 duk__parse_func_like_raw(comp_ctx, flags); /* pushes function template */
68106
68107 /* prev_token.start_offset points to the closing brace here; when skipping
68108 * we're going to reparse the closing brace to ensure semicolon insertion
68109 * etc work as expected.
68110 */
68111 DUK_DDD(DUK_DDDPRINT("after func: prev_tok.start_offset=%ld, curr_tok.start_offset=%ld",
68112 (long) comp_ctx->prev_token.start_offset, (long) comp_ctx->curr_token.start_offset));
68113 DUK_ASSERT(comp_ctx->lex.input[comp_ctx->prev_token.start_offset] == (duk_uint8_t) DUK_ASC_RCURLY);
68114
68115 /* XXX: append primitive */
68116 DUK_ASSERT(duk_get_length(ctx, old_func.funcs_idx) == (duk_size_t) (old_func.fnum_next * 3));
68117 fnum = old_func.fnum_next++;
68118
68119 if (fnum > DUK__MAX_FUNCS) {
68120 DUK_ERROR_RANGE(comp_ctx->thr, DUK_STR_FUNC_LIMIT);
68121 }
68122
68123 /* array writes autoincrement length */
68124 (void) duk_put_prop_index(ctx, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3));
68125 duk_push_size_t(ctx, comp_ctx->prev_token.start_offset);
68126 (void) duk_put_prop_index(ctx, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 1));
68127 duk_push_int(ctx, comp_ctx->prev_token.start_line);
68128 (void) duk_put_prop_index(ctx, old_func.funcs_idx, (duk_uarridx_t) (fnum * 3 + 2));
68129
68130 /*
68131 * Cleanup: restore original function, restore valstack state.
68132 *
68133 * Function declaration handling needs the function name to be pushed
68134 * on the value stack.
68135 */
68136
68137 if (flags & DUK__FUNC_FLAG_PUSHNAME_PASS1) {
68138 DUK_ASSERT(comp_ctx->curr_func.h_name != NULL);
68139 duk_push_hstring(ctx, comp_ctx->curr_func.h_name);
68140 duk_replace(ctx, entry_top);
68141 duk_set_top(ctx, entry_top + 1);
68142 } else {
68143 duk_set_top(ctx, entry_top);
68144 }
68145 DUK_MEMCPY((void *) &comp_ctx->curr_func, (void *) &old_func, sizeof(duk_compiler_func));
68146
68147 return fnum;
68148}
68149
68150/*
68151 * Compile input string into an executable function template without
68152 * arguments.
68153 *
68154 * The string is parsed as the "Program" production of Ecmascript E5.
68155 * Compilation context can be either global code or eval code (see E5
68156 * Sections 14 and 15.1.2.1).
68157 *
68158 * Input stack: [ ... filename ]
68159 * Output stack: [ ... func_template ]
68160 */
68161
68162/* XXX: source code property */
68163
68164DUK_LOCAL duk_ret_t duk__js_compile_raw(duk_context *ctx, void *udata) {
68165 duk_hthread *thr = (duk_hthread *) ctx;
68166 duk_hstring *h_filename;
68167 duk__compiler_stkstate *comp_stk;
68168 duk_compiler_ctx *comp_ctx;
68169 duk_lexer_point *lex_pt;
68170 duk_compiler_func *func;
68171 duk_idx_t entry_top;
68172 duk_bool_t is_strict;
68173 duk_bool_t is_eval;
68174 duk_bool_t is_funcexpr;
68175 duk_small_uint_t flags;
68176
68177 DUK_ASSERT(thr != NULL);
68178 DUK_ASSERT(udata != NULL);
68179
68180 /*
68181 * Arguments check
68182 */
68183
68184 entry_top = duk_get_top(ctx);
68185 DUK_ASSERT(entry_top >= 1);
68186
68187 comp_stk = (duk__compiler_stkstate *) udata;
68188 comp_ctx = &comp_stk->comp_ctx_alloc;
68189 lex_pt = &comp_stk->lex_pt_alloc;
68190 DUK_ASSERT(comp_ctx != NULL);
68191 DUK_ASSERT(lex_pt != NULL);
68192
68193 flags = comp_stk->flags;
68194 is_eval = (flags & DUK_JS_COMPILE_FLAG_EVAL ? 1 : 0);
68195 is_strict = (flags & DUK_JS_COMPILE_FLAG_STRICT ? 1 : 0);
68196 is_funcexpr = (flags & DUK_JS_COMPILE_FLAG_FUNCEXPR ? 1 : 0);
68197
68198 h_filename = duk_get_hstring(ctx, -1); /* may be undefined */
68199
68200 /*
68201 * Init compiler and lexer contexts
68202 */
68203
68204 func = &comp_ctx->curr_func;
68205#if defined(DUK_USE_EXPLICIT_NULL_INIT)
68206 comp_ctx->thr = NULL;
68207 comp_ctx->h_filename = NULL;
68208 comp_ctx->prev_token.str1 = NULL;
68209 comp_ctx->prev_token.str2 = NULL;
68210 comp_ctx->curr_token.str1 = NULL;
68211 comp_ctx->curr_token.str2 = NULL;
68212#endif
68213
68214 duk_require_stack(ctx, DUK__COMPILE_ENTRY_SLOTS);
68215
68216 duk_push_dynamic_buffer(ctx, 0); /* entry_top + 0 */
68217 duk_push_undefined(ctx); /* entry_top + 1 */
68218 duk_push_undefined(ctx); /* entry_top + 2 */
68219 duk_push_undefined(ctx); /* entry_top + 3 */
68220 duk_push_undefined(ctx); /* entry_top + 4 */
68221
68222 comp_ctx->thr = thr;
68223 comp_ctx->h_filename = h_filename;
68224 comp_ctx->tok11_idx = entry_top + 1;
68225 comp_ctx->tok12_idx = entry_top + 2;
68226 comp_ctx->tok21_idx = entry_top + 3;
68227 comp_ctx->tok22_idx = entry_top + 4;
68228 comp_ctx->recursion_limit = DUK_USE_COMPILER_RECLIMIT;
68229
68230 /* comp_ctx->lex has been pre-initialized by caller: it has been
68231 * zeroed and input/input_length has been set.
68232 */
68233 comp_ctx->lex.thr = thr;
68234 /* comp_ctx->lex.input and comp_ctx->lex.input_length filled by caller */
68235 comp_ctx->lex.slot1_idx = comp_ctx->tok11_idx;
68236 comp_ctx->lex.slot2_idx = comp_ctx->tok12_idx;
68237 comp_ctx->lex.buf_idx = entry_top + 0;
68238 comp_ctx->lex.buf = (duk_hbuffer_dynamic *) duk_known_hbuffer(ctx, entry_top + 0);
68239 DUK_ASSERT(DUK_HBUFFER_HAS_DYNAMIC(comp_ctx->lex.buf) && !DUK_HBUFFER_HAS_EXTERNAL(comp_ctx->lex.buf));
68240 comp_ctx->lex.token_limit = DUK_COMPILER_TOKEN_LIMIT;
68241
68242 lex_pt->offset = 0;
68243 lex_pt->line = 1;
68244 DUK_LEXER_SETPOINT(&comp_ctx->lex, lex_pt); /* fills window */
68245 comp_ctx->curr_token.start_line = 0; /* needed for line number tracking (becomes prev_token.start_line) */
68246
68247 /*
68248 * Initialize function state for a zero-argument function
68249 */
68250
68251 duk__init_func_valstack_slots(comp_ctx);
68252 DUK_ASSERT(func->num_formals == 0);
68253
68254 if (is_funcexpr) {
68255 /* Name will be filled from function expression, not by caller.
68256 * This case is used by Function constructor and duk_compile()
68257 * API with the DUK_COMPILE_FUNCTION option.
68258 */
68259 DUK_ASSERT(func->h_name == NULL);
68260 } else {
68261 duk_push_hstring_stridx(ctx, (is_eval ? DUK_STRIDX_EVAL :
68262 DUK_STRIDX_GLOBAL));
68263 func->h_name = duk_get_hstring(ctx, -1);
68264 }
68265
68266 /*
68267 * Parse a function body or a function-like expression, depending
68268 * on flags.
68269 */
68270
68271 DUK_ASSERT(func->is_setget == 0);
68272 func->is_strict = is_strict;
68273 DUK_ASSERT(func->is_notail == 0);
68274
68275 if (is_funcexpr) {
68276 func->is_function = 1;
68277 DUK_ASSERT(func->is_eval == 0);
68278 DUK_ASSERT(func->is_global == 0);
68279 func->is_namebinding = 1;
68280 func->is_constructable = 1;
68281
68282 duk__advance(comp_ctx); /* init 'curr_token' */
68283 duk__advance_expect(comp_ctx, DUK_TOK_FUNCTION);
68284 (void) duk__parse_func_like_raw(comp_ctx, 0 /*flags*/);
68285 } else {
68286 DUK_ASSERT(func->is_function == 0);
68287 func->is_eval = is_eval;
68288 func->is_global = !is_eval;
68289 DUK_ASSERT(func->is_namebinding == 0);
68290 DUK_ASSERT(func->is_constructable == 0);
68291
68292 duk__parse_func_body(comp_ctx,
68293 1, /* expect_eof */
68294 1, /* implicit_return_value */
68295 -1); /* expect_token */
68296 }
68297
68298 /*
68299 * Convert duk_compiler_func to a function template
68300 */
68301
68302 duk__convert_to_func_template(comp_ctx);
68303
68304 /*
68305 * Wrapping duk_safe_call() will mangle the stack, just return stack top
68306 */
68307
68308 /* [ ... filename (temps) func ] */
68309
68310 return 1;
68311}
68312
68313DUK_INTERNAL void duk_js_compile(duk_hthread *thr, const duk_uint8_t *src_buffer, duk_size_t src_length, duk_small_uint_t flags) {
68314 duk_context *ctx = (duk_context *) thr;
68315 duk__compiler_stkstate comp_stk;
68316 duk_compiler_ctx *prev_ctx;
68317 duk_ret_t safe_rc;
68318
68319 DUK_ASSERT(thr != NULL);
68320 DUK_ASSERT(src_buffer != NULL);
68321
68322 /* preinitialize lexer state partially */
68323 DUK_MEMZERO(&comp_stk, sizeof(comp_stk));
68324 comp_stk.flags = flags;
68325 DUK_LEXER_INITCTX(&comp_stk.comp_ctx_alloc.lex);
68326 comp_stk.comp_ctx_alloc.lex.input = src_buffer;
68327 comp_stk.comp_ctx_alloc.lex.input_length = src_length;
68328
68329 /* [ ... filename ] */
68330
68331 prev_ctx = thr->compile_ctx;
68332 thr->compile_ctx = &comp_stk.comp_ctx_alloc; /* for duk_error_augment.c */
68333 safe_rc = duk_safe_call(ctx, duk__js_compile_raw, (void *) &comp_stk /*udata*/, 1 /*nargs*/, 1 /*nret*/);
68334 thr->compile_ctx = prev_ctx; /* must restore reliably before returning */
68335
68336 if (safe_rc != DUK_EXEC_SUCCESS) {
68337 DUK_D(DUK_DPRINT("compilation failed: %!T", duk_get_tval(ctx, -1)));
68338 (void) duk_throw(ctx);
68339 }
68340
68341 /* [ ... template ] */
68342}
68343
68344/* automatic undefs */
68345#undef DUK__ALLOCTEMP
68346#undef DUK__ALLOCTEMPS
68347#undef DUK__ALLOW_AUTO_SEMI_ALWAYS
68348#undef DUK__BC_INITIAL_INSTS
68349#undef DUK__BP_ADDITIVE
68350#undef DUK__BP_ASSIGNMENT
68351#undef DUK__BP_BAND
68352#undef DUK__BP_BOR
68353#undef DUK__BP_BXOR
68354#undef DUK__BP_CALL
68355#undef DUK__BP_CLOSING
68356#undef DUK__BP_COMMA
68357#undef DUK__BP_CONDITIONAL
68358#undef DUK__BP_EOF
68359#undef DUK__BP_EQUALITY
68360#undef DUK__BP_EXPONENTIATION
68361#undef DUK__BP_FOR_EXPR
68362#undef DUK__BP_INVALID
68363#undef DUK__BP_LAND
68364#undef DUK__BP_LOR
68365#undef DUK__BP_MEMBER
68366#undef DUK__BP_MULTIPLICATIVE
68367#undef DUK__BP_POSTFIX
68368#undef DUK__BP_RELATIONAL
68369#undef DUK__BP_SHIFT
68370#undef DUK__COMPILE_ENTRY_SLOTS
68371#undef DUK__CONST_MARKER
68372#undef DUK__DUMP_ISPEC
68373#undef DUK__DUMP_IVALUE
68374#undef DUK__EMIT_FLAG_A_IS_SOURCE
68375#undef DUK__EMIT_FLAG_BC_REGCONST
68376#undef DUK__EMIT_FLAG_B_IS_TARGET
68377#undef DUK__EMIT_FLAG_C_IS_TARGET
68378#undef DUK__EMIT_FLAG_NO_SHUFFLE_A
68379#undef DUK__EMIT_FLAG_NO_SHUFFLE_B
68380#undef DUK__EMIT_FLAG_NO_SHUFFLE_C
68381#undef DUK__EMIT_FLAG_RESERVE_JUMPSLOT
68382#undef DUK__EXPR_FLAG_ALLOW_EMPTY
68383#undef DUK__EXPR_FLAG_REJECT_IN
68384#undef DUK__EXPR_FLAG_REQUIRE_INIT
68385#undef DUK__EXPR_RBP_MASK
68386#undef DUK__FUNCTION_BODY_REQUIRE_SLOTS
68387#undef DUK__FUNCTION_INIT_REQUIRE_SLOTS
68388#undef DUK__FUNC_FLAG_DECL
68389#undef DUK__FUNC_FLAG_GETSET
68390#undef DUK__FUNC_FLAG_METDEF
68391#undef DUK__FUNC_FLAG_PUSHNAME_PASS1
68392#undef DUK__FUNC_FLAG_USE_PREVTOKEN
68393#undef DUK__GETCONST_MAX_CONSTS_CHECK
68394#undef DUK__GETTEMP
68395#undef DUK__HAS_TERM
68396#undef DUK__HAS_VAL
68397#undef DUK__ISCONST
68398#undef DUK__ISREG
68399#undef DUK__ISTEMP
68400#undef DUK__IS_TERMINAL
68401#undef DUK__IVAL_FLAG_ALLOW_CONST
68402#undef DUK__IVAL_FLAG_REQUIRE_SHORT
68403#undef DUK__IVAL_FLAG_REQUIRE_TEMP
68404#undef DUK__MAX_ARRAY_INIT_VALUES
68405#undef DUK__MAX_CONSTS
68406#undef DUK__MAX_FUNCS
68407#undef DUK__MAX_OBJECT_INIT_PAIRS
68408#undef DUK__MAX_TEMPS
68409#undef DUK__MK_LBP
68410#undef DUK__MK_LBP_FLAGS
68411#undef DUK__OBJ_LIT_KEY_GET
68412#undef DUK__OBJ_LIT_KEY_PLAIN
68413#undef DUK__OBJ_LIT_KEY_SET
68414#undef DUK__PARSE_EXPR_SLOTS
68415#undef DUK__PARSE_STATEMENTS_SLOTS
68416#undef DUK__RECURSION_DECREASE
68417#undef DUK__RECURSION_INCREASE
68418#undef DUK__REMOVECONST
68419#undef DUK__SETTEMP
68420#undef DUK__SETTEMP_CHECKMAX
68421#undef DUK__STILL_PROLOGUE
68422#undef DUK__TOKEN_LBP_BP_MASK
68423#undef DUK__TOKEN_LBP_FLAG_NO_REGEXP
68424#undef DUK__TOKEN_LBP_FLAG_TERMINATES
68425#undef DUK__TOKEN_LBP_FLAG_UNUSED
68426#undef DUK__TOKEN_LBP_GET_BP
68427/*
68428 * Ecmascript bytecode executor.
68429 */
68430
68431/* #include duk_internal.h -> already included */
68432
68433/*
68434 * Local declarations.
68435 */
68436
68437DUK_LOCAL_DECL void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_size_t entry_callstack_top);
68438
68439/*
68440 * Misc helpers.
68441 */
68442
68443/* Forced inline declaration, only applied for performance oriented build. */
68444#if defined(DUK_USE_EXEC_PREFER_SIZE)
68445#define DUK__INLINE_PERF
68446#else
68447#define DUK__INLINE_PERF DUK_ALWAYS_INLINE
68448#endif
68449
68450/* Replace value stack top to value at 'tv_ptr'. Optimize for
68451 * performance by only applying the net refcount change.
68452 */
68453#define DUK__REPLACE_TO_TVPTR(thr,tv_ptr) do { \
68454 duk_hthread *duk__thr; \
68455 duk_tval *duk__tvsrc; \
68456 duk_tval *duk__tvdst; \
68457 duk_tval duk__tvtmp; \
68458 duk__thr = (thr); \
68459 duk__tvsrc = DUK_GET_TVAL_NEGIDX((duk_context *) duk__thr, -1); \
68460 duk__tvdst = (tv_ptr); \
68461 DUK_TVAL_SET_TVAL(&duk__tvtmp, duk__tvdst); \
68462 DUK_TVAL_SET_TVAL(duk__tvdst, duk__tvsrc); \
68463 DUK_TVAL_SET_UNDEFINED(duk__tvsrc); /* value stack init policy */ \
68464 duk__thr->valstack_top = duk__tvsrc; \
68465 DUK_TVAL_DECREF(duk__thr, &duk__tvtmp); \
68466 } while (0)
68467
68468/* XXX: candidate of being an internal shared API call */
68469#if !defined(DUK_USE_EXEC_PREFER_SIZE)
68470DUK_LOCAL void duk__push_tvals_incref_only(duk_hthread *thr, duk_tval *tv_src, duk_small_uint_fast_t count) {
68471 duk_tval *tv_dst;
68472 duk_size_t copy_size;
68473 duk_size_t i;
68474
68475 tv_dst = thr->valstack_top;
68476 copy_size = sizeof(duk_tval) * count;
68477 DUK_MEMCPY((void *) tv_dst, (const void *) tv_src, copy_size);
68478 for (i = 0; i < count; i++) {
68479 DUK_TVAL_INCREF(thr, tv_dst);
68480 tv_dst++;
68481 }
68482 thr->valstack_top = tv_dst;
68483}
68484#endif
68485
68486/*
68487 * Arithmetic, binary, and logical helpers.
68488 *
68489 * Note: there is no opcode for logical AND or logical OR; this is on
68490 * purpose, because the evalution order semantics for them make such
68491 * opcodes pretty pointless: short circuiting means they are most
68492 * comfortably implemented as jumps. However, a logical NOT opcode
68493 * is useful.
68494 *
68495 * Note: careful with duk_tval pointers here: they are potentially
68496 * invalidated by any DECREF and almost any API call. It's still
68497 * preferable to work without making a copy but that's not always
68498 * possible.
68499 */
68500
68501DUK_LOCAL DUK__INLINE_PERF duk_double_t duk__compute_mod(duk_double_t d1, duk_double_t d2) {
68502 return (duk_double_t) duk_js_arith_mod((double) d1, (double) d2);
68503}
68504
68505#if defined(DUK_USE_ES7_EXP_OPERATOR)
68506DUK_LOCAL DUK__INLINE_PERF duk_double_t duk__compute_exp(duk_double_t d1, duk_double_t d2) {
68507 return (duk_double_t) duk_js_arith_pow((double) d1, (double) d2);
68508}
68509#endif
68510
68511DUK_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) {
68512 /*
68513 * Addition operator is different from other arithmetic
68514 * operations in that it also provides string concatenation.
68515 * Hence it is implemented separately.
68516 *
68517 * There is a fast path for number addition. Other cases go
68518 * through potentially multiple coercions as described in the
68519 * E5 specification. It may be possible to reduce the number
68520 * of coercions, but this must be done carefully to preserve
68521 * the exact semantics.
68522 *
68523 * E5 Section 11.6.1.
68524 *
68525 * Custom types also have special behavior implemented here.
68526 */
68527
68528 duk_context *ctx = (duk_context *) thr;
68530
68531 DUK_ASSERT(thr != NULL);
68532 DUK_ASSERT(ctx != NULL);
68533 DUK_ASSERT(tv_x != NULL); /* may be reg or const */
68534 DUK_ASSERT(tv_y != NULL); /* may be reg or const */
68535 DUK_ASSERT_DISABLE(idx_z >= 0); /* unsigned */
68536 DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(ctx));
68537
68538 /*
68539 * Fast paths
68540 */
68541
68542#if defined(DUK_USE_FASTINT)
68543 if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
68544 duk_int64_t v1, v2, v3;
68545 duk_int32_t v3_hi;
68546 duk_tval *tv_z;
68547
68548 /* Input values are signed 48-bit so we can detect overflow
68549 * reliably from high bits or just a comparison.
68550 */
68551
68552 v1 = DUK_TVAL_GET_FASTINT(tv_x);
68553 v2 = DUK_TVAL_GET_FASTINT(tv_y);
68554 v3 = v1 + v2;
68555 v3_hi = (duk_int32_t) (v3 >> 32);
68556 if (DUK_LIKELY(v3_hi >= -0x8000LL && v3_hi <= 0x7fffLL)) {
68557 tv_z = thr->valstack_bottom + idx_z;
68558 DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, v3); /* side effects */
68559 return;
68560 } else {
68561 /* overflow, fall through */
68562 ;
68563 }
68564 }
68565#endif /* DUK_USE_FASTINT */
68566
68567 if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
68568#if !defined(DUK_USE_EXEC_PREFER_SIZE)
68569 duk_tval *tv_z;
68570#endif
68571
68572 du.d = DUK_TVAL_GET_NUMBER(tv_x) + DUK_TVAL_GET_NUMBER(tv_y);
68573#if defined(DUK_USE_EXEC_PREFER_SIZE)
68574 duk_push_number(ctx, du.d); /* will NaN normalize result */
68575 duk_replace(ctx, idx_z);
68576#else /* DUK_USE_EXEC_PREFER_SIZE */
68577 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
68578 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
68579 tv_z = thr->valstack_bottom + idx_z;
68580 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, du.d); /* side effects */
68581#endif /* DUK_USE_EXEC_PREFER_SIZE */
68582 return;
68583 }
68584
68585 /*
68586 * Slow path: potentially requires function calls for coercion
68587 */
68588
68589 duk_push_tval(ctx, tv_x);
68590 duk_push_tval(ctx, tv_y);
68591 duk_to_primitive(ctx, -2, DUK_HINT_NONE); /* side effects -> don't use tv_x, tv_y after */
68592 duk_to_primitive(ctx, -1, DUK_HINT_NONE);
68593
68594 /* Since Duktape 2.x plain buffers are treated like ArrayBuffer. */
68595 if (duk_is_string(ctx, -2) || duk_is_string(ctx, -1)) {
68596 /* Symbols shouldn't technically be handled here, but should
68597 * go into the default ToNumber() coercion path instead and
68598 * fail there with a TypeError. However, there's a ToString()
68599 * here which also fails with TypeError so no explicit check
68600 * is needed.
68601 */
68602 duk_to_string(ctx, -2);
68603 duk_to_string(ctx, -1);
68604 duk_concat(ctx, 2); /* [... s1 s2] -> [... s1+s2] */
68605 } else {
68606 duk_double_t d1, d2;
68607
68608 d1 = duk_to_number_m2(ctx);
68609 d2 = duk_to_number_m1(ctx);
68610 DUK_ASSERT(duk_is_number(ctx, -2));
68611 DUK_ASSERT(duk_is_number(ctx, -1));
68612 DUK_ASSERT_DOUBLE_IS_NORMALIZED(d1);
68613 DUK_ASSERT_DOUBLE_IS_NORMALIZED(d2);
68614
68615 du.d = d1 + d2;
68616 duk_pop_2(ctx);
68617 duk_push_number(ctx, du.d); /* will NaN normalize result */
68618 }
68619 duk_replace(ctx, (duk_idx_t) idx_z); /* side effects */
68620}
68621
68622DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_binary_op(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_idx_t idx_z, duk_small_uint_fast_t opcode) {
68623 /*
68624 * Arithmetic operations other than '+' have number-only semantics
68625 * and are implemented here. The separate switch-case here means a
68626 * "double dispatch" of the arithmetic opcode, but saves code space.
68627 *
68628 * E5 Sections 11.5, 11.5.1, 11.5.2, 11.5.3, 11.6, 11.6.1, 11.6.2, 11.6.3.
68629 */
68630
68631 duk_context *ctx = (duk_context *) thr;
68632 duk_double_t d1, d2;
68634 duk_small_uint_fast_t opcode_shifted;
68635#if defined(DUK_USE_FASTINT) || !defined(DUK_USE_EXEC_PREFER_SIZE)
68636 duk_tval *tv_z;
68637#endif
68638
68639 DUK_ASSERT(thr != NULL);
68640 DUK_ASSERT(ctx != NULL);
68641 DUK_ASSERT(tv_x != NULL); /* may be reg or const */
68642 DUK_ASSERT(tv_y != NULL); /* may be reg or const */
68643 DUK_ASSERT_DISABLE(idx_z >= 0); /* unsigned */
68644 DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(ctx));
68645
68646 opcode_shifted = opcode >> 2; /* Get base opcode without reg/const modifiers. */
68647
68648#if defined(DUK_USE_FASTINT)
68649 if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
68650 duk_int64_t v1, v2, v3;
68651 duk_int32_t v3_hi;
68652
68653 v1 = DUK_TVAL_GET_FASTINT(tv_x);
68654 v2 = DUK_TVAL_GET_FASTINT(tv_y);
68655
68656 switch (opcode_shifted) {
68657 case DUK_OP_SUB >> 2: {
68658 v3 = v1 - v2;
68659 break;
68660 }
68661 case DUK_OP_MUL >> 2: {
68662 /* Must ensure result is 64-bit (no overflow); a
68663 * simple and sufficient fast path is to allow only
68664 * 32-bit inputs. Avoid zero inputs to avoid
68665 * negative zero issues (-1 * 0 = -0, for instance).
68666 */
68667 if (v1 >= -0x80000000LL && v1 <= 0x7fffffffLL && v1 != 0 &&
68668 v2 >= -0x80000000LL && v2 <= 0x7fffffffLL && v2 != 0) {
68669 v3 = v1 * v2;
68670 } else {
68671 goto skip_fastint;
68672 }
68673 break;
68674 }
68675 case DUK_OP_DIV >> 2: {
68676 /* Don't allow a zero divisor. Fast path check by
68677 * "verifying" with multiplication. Also avoid zero
68678 * dividend to avoid negative zero issues (0 / -1 = -0
68679 * for instance).
68680 */
68681 if (v1 == 0 || v2 == 0) {
68682 goto skip_fastint;
68683 }
68684 v3 = v1 / v2;
68685 if (v3 * v2 != v1) {
68686 goto skip_fastint;
68687 }
68688 break;
68689 }
68690 case DUK_OP_MOD >> 2: {
68691 /* Don't allow a zero divisor. Restrict both v1 and
68692 * v2 to positive values to avoid compiler specific
68693 * behavior.
68694 */
68695 if (v1 < 1 || v2 < 1) {
68696 goto skip_fastint;
68697 }
68698 v3 = v1 % v2;
68699 DUK_ASSERT(v3 >= 0);
68700 DUK_ASSERT(v3 < v2);
68701 DUK_ASSERT(v1 - (v1 / v2) * v2 == v3);
68702 break;
68703 }
68704 default: {
68705 DUK_UNREACHABLE();
68706 goto skip_fastint;
68707 }
68708 }
68709
68710 v3_hi = (duk_int32_t) (v3 >> 32);
68711 if (DUK_LIKELY(v3_hi >= -0x8000LL && v3_hi <= 0x7fffLL)) {
68712 tv_z = thr->valstack_bottom + idx_z;
68713 DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, v3); /* side effects */
68714 return;
68715 }
68716 /* fall through if overflow etc */
68717 }
68718 skip_fastint:
68719#endif /* DUK_USE_FASTINT */
68720
68721 if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
68722 /* fast path */
68723 d1 = DUK_TVAL_GET_NUMBER(tv_x);
68724 d2 = DUK_TVAL_GET_NUMBER(tv_y);
68725 } else {
68726 duk_push_tval(ctx, tv_x);
68727 duk_push_tval(ctx, tv_y);
68728 d1 = duk_to_number_m2(ctx); /* side effects */
68729 d2 = duk_to_number_m1(ctx);
68730 DUK_ASSERT(duk_is_number(ctx, -2));
68731 DUK_ASSERT(duk_is_number(ctx, -1));
68732 DUK_ASSERT_DOUBLE_IS_NORMALIZED(d1);
68733 DUK_ASSERT_DOUBLE_IS_NORMALIZED(d2);
68734 duk_pop_2(ctx);
68735 }
68736
68737 switch (opcode_shifted) {
68738 case DUK_OP_SUB >> 2: {
68739 du.d = d1 - d2;
68740 break;
68741 }
68742 case DUK_OP_MUL >> 2: {
68743 du.d = d1 * d2;
68744 break;
68745 }
68746 case DUK_OP_DIV >> 2: {
68747 du.d = d1 / d2;
68748 break;
68749 }
68750 case DUK_OP_MOD >> 2: {
68751 du.d = duk__compute_mod(d1, d2);
68752 break;
68753 }
68754#if defined(DUK_USE_ES7_EXP_OPERATOR)
68755 case DUK_OP_EXP >> 2: {
68756 du.d = duk__compute_exp(d1, d2);
68757 break;
68758 }
68759#endif
68760 default: {
68761 DUK_UNREACHABLE();
68762 du.d = DUK_DOUBLE_NAN; /* should not happen */
68763 break;
68764 }
68765 }
68766
68767#if defined(DUK_USE_EXEC_PREFER_SIZE)
68768 duk_push_number(ctx, du.d); /* will NaN normalize result */
68769 duk_replace(ctx, idx_z);
68770#else /* DUK_USE_EXEC_PREFER_SIZE */
68771 /* important to use normalized NaN with 8-byte tagged types */
68772 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du);
68773 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
68774 tv_z = thr->valstack_bottom + idx_z;
68775 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, du.d); /* side effects */
68776#endif /* DUK_USE_EXEC_PREFER_SIZE */
68777}
68778
68779DUK_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) {
68780 /*
68781 * Binary bitwise operations use different coercions (ToInt32, ToUint32)
68782 * depending on the operation. We coerce the arguments first using
68783 * ToInt32(), and then cast to an 32-bit value if necessary. Note that
68784 * such casts must be correct even if there is no native 32-bit type
68785 * (e.g., duk_int32_t and duk_uint32_t are 64-bit).
68786 *
68787 * E5 Sections 11.10, 11.7.1, 11.7.2, 11.7.3
68788 */
68789
68790 duk_context *ctx = (duk_context *) thr;
68791 duk_int32_t i1, i2, i3;
68792 duk_uint32_t u1, u2, u3;
68793#if defined(DUK_USE_FASTINT)
68794 duk_int64_t fi3;
68795#else
68796 duk_double_t d3;
68797#endif
68798 duk_small_uint_fast_t opcode_shifted;
68799#if defined(DUK_USE_FASTINT) || !defined(DUK_USE_EXEC_PREFER_SIZE)
68800 duk_tval *tv_z;
68801#endif
68802
68803 DUK_ASSERT(thr != NULL);
68804 DUK_ASSERT(ctx != NULL);
68805 DUK_ASSERT(tv_x != NULL); /* may be reg or const */
68806 DUK_ASSERT(tv_y != NULL); /* may be reg or const */
68807 DUK_ASSERT_DISABLE(idx_z >= 0); /* unsigned */
68808 DUK_ASSERT((duk_uint_t) idx_z < (duk_uint_t) duk_get_top(ctx));
68809
68810 opcode_shifted = opcode >> 2; /* Get base opcode without reg/const modifiers. */
68811
68812#if defined(DUK_USE_FASTINT)
68813 if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
68814 i1 = (duk_int32_t) DUK_TVAL_GET_FASTINT_I32(tv_x);
68815 i2 = (duk_int32_t) DUK_TVAL_GET_FASTINT_I32(tv_y);
68816 }
68817 else
68818#endif /* DUK_USE_FASTINT */
68819 {
68820 duk_push_tval(ctx, tv_x);
68821 duk_push_tval(ctx, tv_y);
68822 i1 = duk_to_int32(ctx, -2);
68823 i2 = duk_to_int32(ctx, -1);
68824 duk_pop_2(ctx);
68825 }
68826
68827 switch (opcode_shifted) {
68828 case DUK_OP_BAND >> 2: {
68829 i3 = i1 & i2;
68830 break;
68831 }
68832 case DUK_OP_BOR >> 2: {
68833 i3 = i1 | i2;
68834 break;
68835 }
68836 case DUK_OP_BXOR >> 2: {
68837 i3 = i1 ^ i2;
68838 break;
68839 }
68840 case DUK_OP_BASL >> 2: {
68841 /* Signed shift, named "arithmetic" (asl) because the result
68842 * is signed, e.g. 4294967295 << 1 -> -2. Note that result
68843 * must be masked.
68844 */
68845
68846 u2 = ((duk_uint32_t) i2) & 0xffffffffUL;
68847 i3 = (duk_int32_t) (((duk_uint32_t) i1) << (u2 & 0x1fUL)); /* E5 Section 11.7.1, steps 7 and 8 */
68848 i3 = i3 & ((duk_int32_t) 0xffffffffUL); /* Note: left shift, should mask */
68849 break;
68850 }
68851 case DUK_OP_BASR >> 2: {
68852 /* signed shift */
68853
68854 u2 = ((duk_uint32_t) i2) & 0xffffffffUL;
68855 i3 = i1 >> (u2 & 0x1fUL); /* E5 Section 11.7.2, steps 7 and 8 */
68856 break;
68857 }
68858 case DUK_OP_BLSR >> 2: {
68859 /* unsigned shift */
68860
68861 u1 = ((duk_uint32_t) i1) & 0xffffffffUL;
68862 u2 = ((duk_uint32_t) i2) & 0xffffffffUL;
68863
68864 /* special result value handling */
68865 u3 = u1 >> (u2 & 0x1fUL); /* E5 Section 11.7.2, steps 7 and 8 */
68866#if defined(DUK_USE_FASTINT)
68867 fi3 = (duk_int64_t) u3;
68868 goto fastint_result_set;
68869#else
68870 d3 = (duk_double_t) u3;
68871 goto result_set;
68872#endif
68873 }
68874 default: {
68875 DUK_UNREACHABLE();
68876 i3 = 0; /* should not happen */
68877 break;
68878 }
68879 }
68880
68881#if defined(DUK_USE_FASTINT)
68882 /* Result is always fastint compatible. */
68883 /* XXX: Set 32-bit result (but must then handle signed and
68884 * unsigned results separately).
68885 */
68886 fi3 = (duk_int64_t) i3;
68887
68888 fastint_result_set:
68889 tv_z = thr->valstack_bottom + idx_z;
68890 DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_z, fi3); /* side effects */
68891#else /* DUK_USE_FASTINT */
68892 d3 = (duk_double_t) i3;
68893
68894 result_set:
68895 DUK_ASSERT(!DUK_ISNAN(d3)); /* 'd3' is never NaN, so no need to normalize */
68896 DUK_ASSERT_DOUBLE_IS_NORMALIZED(d3); /* always normalized */
68897
68898#if defined(DUK_USE_EXEC_PREFER_SIZE)
68899 duk_push_number(ctx, d3); /* would NaN normalize result, but unnecessary */
68900 duk_replace(ctx, idx_z);
68901#else /* DUK_USE_EXEC_PREFER_SIZE */
68902 tv_z = thr->valstack_bottom + idx_z;
68903 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_z, d3); /* side effects */
68904#endif /* DUK_USE_EXEC_PREFER_SIZE */
68905#endif /* DUK_USE_FASTINT */
68906}
68907
68908/* In-place unary operation. */
68909DUK_LOCAL DUK__INLINE_PERF void duk__vm_arith_unary_op(duk_hthread *thr, duk_idx_t idx_src, duk_idx_t idx_dst, duk_small_uint_fast_t opcode) {
68910 /*
68911 * Arithmetic operations other than '+' have number-only semantics
68912 * and are implemented here. The separate switch-case here means a
68913 * "double dispatch" of the arithmetic opcode, but saves code space.
68914 *
68915 * E5 Sections 11.5, 11.5.1, 11.5.2, 11.5.3, 11.6, 11.6.1, 11.6.2, 11.6.3.
68916 */
68917
68918 duk_context *ctx = (duk_context *) thr;
68919 duk_tval *tv;
68920 duk_double_t d1;
68922
68923 DUK_ASSERT(thr != NULL);
68924 DUK_ASSERT(ctx != NULL);
68925 DUK_ASSERT(opcode == DUK_OP_UNM || opcode == DUK_OP_UNP);
68926 DUK_ASSERT(idx_src >= 0);
68927 DUK_ASSERT(idx_dst >= 0);
68928
68929 tv = DUK_GET_TVAL_POSIDX(ctx, idx_src);
68930
68931#if defined(DUK_USE_FASTINT)
68932 if (DUK_TVAL_IS_FASTINT(tv)) {
68933 duk_int64_t v1, v2;
68934
68935 v1 = DUK_TVAL_GET_FASTINT(tv);
68936 if (opcode == DUK_OP_UNM) {
68937 /* The smallest fastint is no longer 48-bit when
68938 * negated. Positive zero becames negative zero
68939 * (cannot be represented) when negated.
68940 */
68941 if (DUK_LIKELY(v1 != DUK_FASTINT_MIN && v1 != 0)) {
68942 v2 = -v1;
68943 tv = DUK_GET_TVAL_POSIDX(ctx, idx_dst);
68944 DUK_TVAL_SET_FASTINT_UPDREF(thr, tv, v2);
68945 return;
68946 }
68947 } else {
68948 /* ToNumber() for a fastint is a no-op. */
68949 DUK_ASSERT(opcode == DUK_OP_UNP);
68950 v2 = v1;
68951 tv = DUK_GET_TVAL_POSIDX(ctx, idx_dst);
68952 DUK_TVAL_SET_FASTINT_UPDREF(thr, tv, v2);
68953 return;
68954 }
68955 /* fall through if overflow etc */
68956 }
68957#endif /* DUK_USE_FASTINT */
68958
68959 if (DUK_TVAL_IS_NUMBER(tv)) {
68960 d1 = DUK_TVAL_GET_NUMBER(tv);
68961 } else {
68962 d1 = duk_to_number(ctx, idx_src); /* side effects, perform in-place */
68963 DUK_ASSERT(DUK_TVAL_IS_NUMBER(DUK_GET_TVAL_POSIDX(ctx, idx_src)));
68964 }
68965
68966 if (opcode == DUK_OP_UNP) {
68967 /* ToNumber() for a double is a no-op, but unary plus is
68968 * used to force a fastint check so do that here.
68969 */
68970 du.d = d1;
68971 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
68972#if defined(DUK_USE_FASTINT)
68973 tv = DUK_GET_TVAL_POSIDX(ctx, idx_dst);
68974 DUK_TVAL_SET_NUMBER_CHKFAST_UPDREF(thr, tv, du.d); /* always 'fast', i.e. inlined */
68975 return;
68976#endif
68977 } else {
68978 DUK_ASSERT(opcode == DUK_OP_UNM);
68979 du.d = -d1;
68980 DUK_DBLUNION_NORMALIZE_NAN_CHECK(&du); /* mandatory if du.d is a NaN */
68981 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
68982 }
68983
68984 /* XXX: size optimize: push+replace? */
68985 tv = DUK_GET_TVAL_POSIDX(ctx, idx_dst);
68986 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv, du.d);
68987}
68988
68989DUK_LOCAL DUK__INLINE_PERF void duk__vm_bitwise_not(duk_hthread *thr, duk_uint_fast_t idx_src, duk_uint_fast_t idx_dst) {
68990 /*
68991 * E5 Section 11.4.8
68992 */
68993
68994 duk_context *ctx = (duk_context *) thr;
68995 duk_tval *tv;
68996 duk_int32_t i1, i2;
68997
68998 DUK_ASSERT(thr != NULL);
68999 DUK_ASSERT(ctx != NULL);
69000 DUK_ASSERT_DISABLE(idx_src >= 0);
69001 DUK_ASSERT_DISABLE(idx_dst >= 0);
69002 DUK_ASSERT((duk_uint_t) idx_src < (duk_uint_t) duk_get_top(ctx));
69003 DUK_ASSERT((duk_uint_t) idx_dst < (duk_uint_t) duk_get_top(ctx));
69004 DUK_UNREF(thr); /* w/o refcounts */
69005
69006 tv = DUK_GET_TVAL_POSIDX(ctx, idx_src);
69007
69008#if defined(DUK_USE_FASTINT)
69009 if (DUK_TVAL_IS_FASTINT(tv)) {
69010 i1 = (duk_int32_t) DUK_TVAL_GET_FASTINT_I32(tv);
69011 }
69012 else
69013#endif /* DUK_USE_FASTINT */
69014 {
69015 i1 = duk_to_int32(ctx, idx_src); /* side effects */
69016 }
69017
69018 /* Result is always fastint compatible. */
69019 i2 = ~i1;
69020 tv = DUK_GET_TVAL_POSIDX(ctx, idx_dst);
69021 DUK_TVAL_SET_I32_UPDREF(thr, tv, i2); /* side effects */
69022}
69023
69024DUK_LOCAL DUK__INLINE_PERF void duk__vm_logical_not(duk_hthread *thr, duk_idx_t idx_src, duk_idx_t idx_dst) {
69025 /*
69026 * E5 Section 11.4.9
69027 */
69028
69029 duk_context *ctx = (duk_context *) thr;
69030 duk_tval *tv;
69031 duk_bool_t res;
69032
69033 DUK_ASSERT(thr != NULL);
69034 DUK_ASSERT(ctx != NULL);
69035 DUK_ASSERT_DISABLE(idx_src >= 0);
69036 DUK_ASSERT_DISABLE(idx_dst >= 0);
69037 DUK_ASSERT((duk_uint_t) idx_src < (duk_uint_t) duk_get_top(ctx));
69038 DUK_ASSERT((duk_uint_t) idx_dst < (duk_uint_t) duk_get_top(ctx));
69039 DUK_UNREF(thr); /* w/o refcounts */
69040
69041 /* ToBoolean() does not require any operations with side effects so
69042 * we can do it efficiently. For footprint it would be better to use
69043 * duk_js_toboolean() and then push+replace to the result slot.
69044 */
69045 tv = DUK_GET_TVAL_POSIDX(ctx, idx_src);
69046 res = duk_js_toboolean(tv); /* does not modify 'tv' */
69047 DUK_ASSERT(res == 0 || res == 1);
69048 res ^= 1;
69049 tv = DUK_GET_TVAL_POSIDX(ctx, idx_dst);
69050 /* XXX: size optimize: push+replace? */
69051 DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv, res); /* side effects */
69052}
69053
69054/* XXX: size optimized variant */
69055DUK_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) {
69056 duk_context *ctx = (duk_context *) thr;
69057 duk_double_t x, y, z;
69058
69059 /* Two lowest bits of opcode are used to distinguish
69060 * variants. Bit 0 = inc(0)/dec(1), bit 1 = pre(0)/post(1).
69061 */
69062 DUK_ASSERT((DUK_OP_PREINCR & 0x03) == 0x00);
69063 DUK_ASSERT((DUK_OP_PREDECR & 0x03) == 0x01);
69064 DUK_ASSERT((DUK_OP_POSTINCR & 0x03) == 0x02);
69065 DUK_ASSERT((DUK_OP_POSTDECR & 0x03) == 0x03);
69066
69067#if defined(DUK_USE_FASTINT)
69068 if (DUK_TVAL_IS_FASTINT(tv_src)) {
69069 duk_int64_t x_fi, y_fi, z_fi;
69070 x_fi = DUK_TVAL_GET_FASTINT(tv_src);
69071 if (op & 0x01) {
69072 if (DUK_UNLIKELY(x_fi == DUK_FASTINT_MIN)) {
69073 goto skip_fastint;
69074 }
69075 y_fi = x_fi - 1;
69076 } else {
69077 if (DUK_UNLIKELY(x_fi == DUK_FASTINT_MAX)) {
69078 goto skip_fastint;
69079 }
69080 y_fi = x_fi + 1;
69081 }
69082
69083 DUK_TVAL_SET_FASTINT(tv_src, y_fi); /* no need for refcount update */
69084
69085 z_fi = (op & 0x02) ? x_fi : y_fi;
69086 DUK_TVAL_SET_FASTINT_UPDREF(thr, tv_dst, z_fi); /* side effects */
69087 return;
69088 }
69089 skip_fastint:
69090#endif
69091 if (DUK_TVAL_IS_NUMBER(tv_src)) {
69092 /* Fast path for the case where the register
69093 * is a number (e.g. loop counter).
69094 */
69095
69096 x = DUK_TVAL_GET_NUMBER(tv_src);
69097 if (op & 0x01) {
69098 y = x - 1.0;
69099 } else {
69100 y = x + 1.0;
69101 }
69102
69103 DUK_TVAL_SET_NUMBER(tv_src, y); /* no need for refcount update */
69104 } else {
69105 /* Preserve duk_tval pointer(s) across a potential valstack
69106 * resize by converting them into offsets temporarily.
69107 */
69108 duk_idx_t bc;
69109 duk_size_t off_dst;
69110
69111 off_dst = (duk_size_t) ((duk_uint8_t *) tv_dst - (duk_uint8_t *) thr->valstack_bottom);
69112 bc = (duk_idx_t) (tv_src - thr->valstack_bottom); /* XXX: pass index explicitly? */
69113 tv_src = NULL; /* no longer referenced */
69114
69115 x = duk_to_number(ctx, bc);
69116 if (op & 0x01) {
69117 y = x - 1.0;
69118 } else {
69119 y = x + 1.0;
69120 }
69121
69122 duk_push_number(ctx, y);
69123 duk_replace(ctx, bc);
69124
69125 tv_dst = (duk_tval *) (void *) (((duk_uint8_t *) thr->valstack_bottom) + off_dst);
69126 }
69127
69128 z = (op & 0x02) ? x : y;
69129 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_dst, z); /* side effects */
69130}
69131
69132DUK_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_uint_t is_strict) {
69133 duk_context *ctx = (duk_context *) thr;
69134 duk_activation *act;
69135 duk_double_t x, y;
69136 duk_hstring *name;
69137
69138 /* XXX: The pre/post inc/dec for an identifier lookup is
69139 * missing the important fast path where the identifier
69140 * has a storage location e.g. in a scope object so that
69141 * it can be updated in-place. In particular, the case
69142 * where the identifier has a storage location AND the
69143 * previous value is a number should be optimized because
69144 * it's side effect free.
69145 */
69146
69147 /* Two lowest bits of opcode are used to distinguish
69148 * variants. Bit 0 = inc(0)/dec(1), bit 1 = pre(0)/post(1).
69149 */
69150 DUK_ASSERT((DUK_OP_PREINCV & 0x03) == 0x00);
69151 DUK_ASSERT((DUK_OP_PREDECV & 0x03) == 0x01);
69152 DUK_ASSERT((DUK_OP_POSTINCV & 0x03) == 0x02);
69153 DUK_ASSERT((DUK_OP_POSTDECV & 0x03) == 0x03);
69154
69155 DUK_ASSERT(DUK_TVAL_IS_STRING(tv_id));
69156 name = DUK_TVAL_GET_STRING(tv_id);
69157 DUK_ASSERT(name != NULL);
69158 act = thr->callstack + thr->callstack_top - 1;
69159 (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [ ... val this ] */
69160
69161 /* XXX: Fastint fast path would be useful here. Also fastints
69162 * now lose their fastint status in current handling which is
69163 * not intuitive.
69164 */
69165
69166 x = duk_to_number_m2(ctx);
69167 if (op & 0x01) {
69168 y = x - 1.0;
69169 } else {
69170 y = x + 1.0;
69171 }
69172
69173 /* [... x this] */
69174
69175 if (op & 0x02) {
69176 duk_push_number(ctx, y); /* -> [ ... x this y ] */
69177 duk_js_putvar_activation(thr, act, name, DUK_GET_TVAL_NEGIDX(ctx, -1), is_strict);
69178 duk_pop_2(ctx); /* -> [ ... x ] */
69179 } else {
69180 duk_pop_2(ctx); /* -> [ ... ] */
69181 duk_push_number(ctx, y); /* -> [ ... y ] */
69182 duk_js_putvar_activation(thr, act, name, DUK_GET_TVAL_NEGIDX(ctx, -1), is_strict);
69183 }
69184
69185#if defined(DUK_USE_EXEC_PREFER_SIZE)
69186 duk_replace(ctx, (duk_idx_t) idx_dst);
69187#else /* DUK_USE_EXEC_PREFER_SIZE */
69188 DUK__REPLACE_TO_TVPTR(thr, DUK_GET_TVAL_POSIDX(ctx, idx_dst));
69189#endif /* DUK_USE_EXEC_PREFER_SIZE */
69190}
69191
69192/*
69193 * Longjmp and other control flow transfer for the bytecode executor.
69194 *
69195 * The longjmp handler can handle all longjmp types: error, yield, and
69196 * resume (pseudotypes are never actually thrown).
69197 *
69198 * Error policy for longjmp: should not ordinarily throw errors; if errors
69199 * occur (e.g. due to out-of-memory) they bubble outwards rather than being
69200 * handled recursively.
69201 */
69202
69203#define DUK__LONGJMP_RESTART 0 /* state updated, restart bytecode execution */
69204#define DUK__LONGJMP_RETHROW 1 /* exit bytecode executor by rethrowing an error to caller */
69205
69206#define DUK__RETHAND_RESTART 0 /* state updated, restart bytecode execution */
69207#define DUK__RETHAND_FINISHED 1 /* exit bytecode execution with return value */
69208
69209/* XXX: optimize reconfig valstack operations so that resize, clamp, and setting
69210 * top are combined into one pass.
69211 */
69212
69213/* Reconfigure value stack for return to an Ecmascript function at 'act_idx'. */
69214DUK_LOCAL void duk__reconfig_valstack_ecma_return(duk_hthread *thr, duk_size_t act_idx) {
69215 duk_activation *act;
69216 duk_hcompfunc *h_func;
69217 duk_idx_t clamp_top;
69218
69219 DUK_ASSERT(thr != NULL);
69220 DUK_ASSERT_DISABLE(act_idx >= 0); /* unsigned */
69221 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + act_idx) != NULL);
69222 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + act_idx)));
69223 DUK_ASSERT_DISABLE(thr->callstack[act_idx].idx_retval >= 0); /* unsigned */
69224
69225 /* Clamp so that values at 'clamp_top' and above are wiped and won't
69226 * retain reachable garbage. Then extend to 'nregs' because we're
69227 * returning to an Ecmascript function.
69228 */
69229
69230 act = thr->callstack + act_idx;
69231 h_func = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
69232
69233 thr->valstack_bottom = thr->valstack + act->idx_bottom;
69234 DUK_ASSERT(act->idx_retval >= act->idx_bottom);
69235 clamp_top = (duk_idx_t) (act->idx_retval - act->idx_bottom + 1); /* +1 = one retval */
69236 duk_set_top((duk_context *) thr, clamp_top);
69237 act = NULL;
69238
69239 (void) duk_valstack_resize_raw((duk_context *) thr,
69240 (thr->valstack_bottom - thr->valstack) + /* bottom of current func */
69241 h_func->nregs + /* reg count */
69242 DUK_VALSTACK_INTERNAL_EXTRA, /* + spare */
69243 DUK_VSRESIZE_FLAG_SHRINK | /* flags */
69244 0 /* no compact */ |
69245 DUK_VSRESIZE_FLAG_THROW);
69246
69247 duk_set_top((duk_context *) thr, h_func->nregs);
69248}
69249
69250DUK_LOCAL void duk__reconfig_valstack_ecma_catcher(duk_hthread *thr, duk_size_t act_idx, duk_size_t cat_idx) {
69251 duk_activation *act;
69252 duk_catcher *cat;
69253 duk_hcompfunc *h_func;
69254 duk_idx_t clamp_top;
69255
69256 DUK_ASSERT(thr != NULL);
69257 DUK_ASSERT_DISABLE(act_idx >= 0); /* unsigned */
69258 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + act_idx) != NULL);
69259 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + act_idx)));
69260 DUK_ASSERT_DISABLE(thr->callstack[act_idx].idx_retval >= 0); /* unsigned */
69261
69262 act = thr->callstack + act_idx;
69263 cat = thr->catchstack + cat_idx;
69264 h_func = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
69265
69266 thr->valstack_bottom = thr->valstack + act->idx_bottom;
69267 DUK_ASSERT(cat->idx_base >= act->idx_bottom);
69268 clamp_top = (duk_idx_t) (cat->idx_base - act->idx_bottom + 2); /* +2 = catcher value, catcher lj_type */
69269 duk_set_top((duk_context *) thr, clamp_top);
69270 act = NULL;
69271 cat = NULL;
69272
69273 (void) duk_valstack_resize_raw((duk_context *) thr,
69274 (thr->valstack_bottom - thr->valstack) + /* bottom of current func */
69275 h_func->nregs + /* reg count */
69276 DUK_VALSTACK_INTERNAL_EXTRA, /* + spare */
69277 DUK_VSRESIZE_FLAG_SHRINK | /* flags */
69278 0 /* no compact */ |
69279 DUK_VSRESIZE_FLAG_THROW);
69280
69281 duk_set_top((duk_context *) thr, h_func->nregs);
69282}
69283
69284/* Set catcher regs: idx_base+0 = value, idx_base+1 = lj_type. */
69285DUK_LOCAL void duk__set_catcher_regs(duk_hthread *thr, duk_size_t cat_idx, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) {
69286 duk_tval *tv1;
69287
69288 DUK_ASSERT(thr != NULL);
69289 DUK_ASSERT(tv_val_unstable != NULL);
69290
69291 tv1 = thr->valstack + thr->catchstack[cat_idx].idx_base;
69292 DUK_ASSERT(tv1 < thr->valstack_top);
69293 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv_val_unstable); /* side effects */
69294
69295 tv1 = thr->valstack + thr->catchstack[cat_idx].idx_base + 1;
69296 DUK_ASSERT(tv1 < thr->valstack_top);
69297
69298 DUK_TVAL_SET_U32_UPDREF(thr, tv1, (duk_uint32_t) lj_type); /* side effects */
69299}
69300
69301DUK_LOCAL void duk__handle_catch(duk_hthread *thr, duk_size_t cat_idx, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) {
69302 duk_context *ctx;
69303 duk_activation *act;
69304
69305 DUK_ASSERT(thr != NULL);
69306 DUK_ASSERT(tv_val_unstable != NULL);
69307 ctx = (duk_context *) thr;
69308
69309 duk__set_catcher_regs(thr, cat_idx, tv_val_unstable, lj_type);
69310
69311 duk_hthread_catchstack_unwind(thr, cat_idx + 1);
69312 duk_hthread_callstack_unwind(thr, thr->catchstack[cat_idx].callstack_index + 1);
69313
69314 DUK_ASSERT(thr->callstack_top >= 1);
69315 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL);
69316 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)));
69317
69318 duk__reconfig_valstack_ecma_catcher(thr, thr->callstack_top - 1, cat_idx);
69319
69320 DUK_ASSERT(thr->callstack_top >= 1);
69321 act = thr->callstack + thr->callstack_top - 1;
69322 act->curr_pc = thr->catchstack[cat_idx].pc_base + 0; /* +0 = catch */
69323 act = NULL;
69324
69325 /*
69326 * If entering a 'catch' block which requires an automatic
69327 * catch variable binding, create the lexical environment.
69328 *
69329 * The binding is mutable (= writable) but not deletable.
69330 * Step 4 for the catch production in E5 Section 12.14;
69331 * no value is given for CreateMutableBinding 'D' argument,
69332 * which implies the binding is not deletable.
69333 */
69334
69335 if (DUK_CAT_HAS_CATCH_BINDING_ENABLED(&thr->catchstack[cat_idx])) {
69336 duk_hobject *new_env;
69337 duk_hobject *act_lex_env;
69338
69339 DUK_DDD(DUK_DDDPRINT("catcher has an automatic catch binding"));
69340
69341 /* Note: 'act' is dangerous here because it may get invalidate at many
69342 * points, so we re-lookup it multiple times.
69343 */
69344 DUK_ASSERT(thr->callstack_top >= 1);
69345 act = thr->callstack + thr->callstack_top - 1;
69346
69347 if (act->lex_env == NULL) {
69348 DUK_ASSERT(act->var_env == NULL);
69349 DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
69350
69351 /* this may have side effects, so re-lookup act */
69352 duk_js_init_activation_environment_records_delayed(thr, act);
69353 act = thr->callstack + thr->callstack_top - 1;
69354 }
69355 DUK_ASSERT(act->lex_env != NULL);
69356 DUK_ASSERT(act->var_env != NULL);
69357 DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
69358 DUK_UNREF(act); /* unreferenced without assertions */
69359
69360 act = thr->callstack + thr->callstack_top - 1;
69361 act_lex_env = act->lex_env;
69362 act = NULL; /* invalidated */
69363
69364 new_env = duk_push_object_helper_proto(ctx,
69365 DUK_HOBJECT_FLAG_EXTENSIBLE |
69366 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
69367 act_lex_env);
69368 DUK_ASSERT(new_env != NULL);
69369 DUK_DDD(DUK_DDDPRINT("new_env allocated: %!iO", (duk_heaphdr *) new_env));
69370
69371 /* Note: currently the catch binding is handled without a register
69372 * binding because we don't support dynamic register bindings (they
69373 * must be fixed for an entire function). So, there is no need to
69374 * record regbases etc.
69375 */
69376
69377 DUK_ASSERT(thr->catchstack[cat_idx].h_varname != NULL);
69378 duk_push_hstring(ctx, thr->catchstack[cat_idx].h_varname);
69379 duk_push_tval(ctx, thr->valstack + thr->catchstack[cat_idx].idx_base);
69380 duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_W); /* writable, not configurable */
69381
69382 act = thr->callstack + thr->callstack_top - 1;
69383 act->lex_env = new_env;
69384 DUK_HOBJECT_INCREF(thr, new_env); /* reachable through activation */
69385
69386 DUK_CAT_SET_LEXENV_ACTIVE(&thr->catchstack[cat_idx]);
69387
69388 duk_pop(ctx);
69389
69390 DUK_DDD(DUK_DDDPRINT("new_env finished: %!iO", (duk_heaphdr *) new_env));
69391 }
69392
69393 DUK_CAT_CLEAR_CATCH_ENABLED(&thr->catchstack[cat_idx]);
69394}
69395
69396DUK_LOCAL void duk__handle_finally(duk_hthread *thr, duk_size_t cat_idx, duk_tval *tv_val_unstable, duk_small_uint_t lj_type) {
69397 duk_activation *act;
69398
69399 DUK_ASSERT(thr != NULL);
69400 DUK_ASSERT(tv_val_unstable != NULL);
69401
69402 duk__set_catcher_regs(thr, cat_idx, tv_val_unstable, lj_type);
69403
69404 duk_hthread_catchstack_unwind(thr, cat_idx + 1); /* cat_idx catcher is kept, even for finally */
69405 duk_hthread_callstack_unwind(thr, thr->catchstack[cat_idx].callstack_index + 1);
69406
69407 DUK_ASSERT(thr->callstack_top >= 1);
69408 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL);
69409 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)));
69410
69411 duk__reconfig_valstack_ecma_catcher(thr, thr->callstack_top - 1, cat_idx);
69412
69413 DUK_ASSERT(thr->callstack_top >= 1);
69414 act = thr->callstack + thr->callstack_top - 1;
69415 act->curr_pc = thr->catchstack[cat_idx].pc_base + 1; /* +1 = finally */
69416 act = NULL;
69417
69418 DUK_CAT_CLEAR_FINALLY_ENABLED(&thr->catchstack[cat_idx]);
69419}
69420
69421DUK_LOCAL void duk__handle_label(duk_hthread *thr, duk_size_t cat_idx, duk_small_uint_t lj_type) {
69422 duk_activation *act;
69423
69424 DUK_ASSERT(thr != NULL);
69425
69426 DUK_ASSERT(thr->callstack_top >= 1);
69427 act = thr->callstack + thr->callstack_top - 1;
69428
69429 DUK_ASSERT(DUK_ACT_GET_FUNC(act) != NULL);
69430 DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(DUK_ACT_GET_FUNC(act)));
69431
69432 /* +0 = break, +1 = continue */
69433 act->curr_pc = thr->catchstack[cat_idx].pc_base + (lj_type == DUK_LJ_TYPE_CONTINUE ? 1 : 0);
69434 act = NULL; /* invalidated */
69435
69436 duk_hthread_catchstack_unwind(thr, cat_idx + 1); /* keep label catcher */
69437 /* no need to unwind callstack */
69438
69439 /* valstack should not need changes */
69440#if defined(DUK_USE_ASSERTIONS)
69441 DUK_ASSERT(thr->callstack_top >= 1);
69442 act = thr->callstack + thr->callstack_top - 1;
69443 DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack_bottom) ==
69444 (duk_size_t) ((duk_hcompfunc *) DUK_ACT_GET_FUNC(act))->nregs);
69445#endif
69446}
69447
69448/* Called for handling both a longjmp() with type DUK_LJ_TYPE_YIELD and
69449 * when a RETURN opcode terminates a thread and yields to the resumer.
69450 */
69451#if defined(DUK_USE_COROUTINE_SUPPORT)
69452DUK_LOCAL void duk__handle_yield(duk_hthread *thr, duk_hthread *resumer, duk_size_t act_idx, duk_tval *tv_val_unstable) {
69453 duk_tval *tv1;
69454
69455 DUK_ASSERT(thr != NULL);
69456 DUK_ASSERT(resumer != NULL);
69457 DUK_ASSERT(tv_val_unstable != NULL);
69458 DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack + act_idx) != NULL);
69459 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(resumer->callstack + act_idx))); /* resume caller must be an ecmascript func */
69460
69461 tv1 = resumer->valstack + resumer->callstack[act_idx].idx_retval; /* return value from Duktape.Thread.resume() */
69462 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv_val_unstable); /* side effects */
69463
69464 duk_hthread_callstack_unwind(resumer, act_idx + 1); /* unwind to 'resume' caller */
69465
69466 /* no need to unwind catchstack */
69467 duk__reconfig_valstack_ecma_return(resumer, act_idx);
69468
69469 /* caller must change active thread, and set thr->resumer to NULL */
69470}
69471#endif /* DUK_USE_COROUTINE_SUPPORT */
69472
69473DUK_LOCAL
69474duk_small_uint_t duk__handle_longjmp(duk_hthread *thr,
69475 duk_hthread *entry_thread,
69476 duk_size_t entry_callstack_top) {
69477 duk_size_t entry_callstack_index;
69478 duk_small_uint_t retval = DUK__LONGJMP_RESTART;
69479
69480 DUK_ASSERT(thr != NULL);
69481 DUK_ASSERT(entry_thread != NULL);
69482 DUK_ASSERT(entry_callstack_top > 0); /* guarantees entry_callstack_top - 1 >= 0 */
69483
69484 entry_callstack_index = entry_callstack_top - 1;
69485
69486 /* 'thr' is the current thread, as no-one resumes except us and we
69487 * switch 'thr' in that case.
69488 */
69489 DUK_ASSERT(thr == thr->heap->curr_thread);
69490
69491 /*
69492 * (Re)try handling the longjmp.
69493 *
69494 * A longjmp handler may convert the longjmp to a different type and
69495 * "virtually" rethrow by goto'ing to 'check_longjmp'. Before the goto,
69496 * the following must be updated:
69497 * - the heap 'lj' state
69498 * - 'thr' must reflect the "throwing" thread
69499 */
69500
69501 check_longjmp:
69502
69503 DUK_DD(DUK_DDPRINT("handling longjmp: type=%ld, value1=%!T, value2=%!T, iserror=%ld",
69504 (long) thr->heap->lj.type,
69505 (duk_tval *) &thr->heap->lj.value1,
69506 (duk_tval *) &thr->heap->lj.value2,
69507 (long) thr->heap->lj.iserror));
69508
69509 switch (thr->heap->lj.type) {
69510
69511#if defined(DUK_USE_COROUTINE_SUPPORT)
69512 case DUK_LJ_TYPE_RESUME: {
69513 /*
69514 * Note: lj.value1 is 'value', lj.value2 is 'resumee'.
69515 * This differs from YIELD.
69516 */
69517
69518 duk_tval *tv;
69519 duk_tval *tv2;
69520 duk_size_t act_idx;
69521 duk_hthread *resumee;
69522
69523 /* duk_bi_duk_object_yield() and duk_bi_duk_object_resume() ensure all of these are met */
69524
69525 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged by Duktape.Thread.resume() */
69526 DUK_ASSERT(thr->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */
69527 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL &&
69528 DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)) &&
69529 ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))->func == duk_bi_thread_resume);
69530 DUK_ASSERT_DISABLE((thr->callstack + thr->callstack_top - 2)->idx_retval >= 0); /* unsigned */
69531
69532 tv = &thr->heap->lj.value2; /* resumee */
69533 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
69534 DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL);
69535 DUK_ASSERT(DUK_HOBJECT_IS_THREAD(DUK_TVAL_GET_OBJECT(tv)));
69536 resumee = (duk_hthread *) DUK_TVAL_GET_OBJECT(tv);
69537
69538 DUK_ASSERT(resumee != NULL);
69539 DUK_ASSERT(resumee->resumer == NULL);
69540 DUK_ASSERT(resumee->state == DUK_HTHREAD_STATE_INACTIVE ||
69541 resumee->state == DUK_HTHREAD_STATE_YIELDED); /* checked by Duktape.Thread.resume() */
69542 DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
69543 resumee->callstack_top >= 2); /* YIELDED: Ecmascript activation + Duktape.Thread.yield() activation */
69544 DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
69545 (DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 1) != NULL &&
69546 DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 1)) &&
69547 ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumee->callstack + resumee->callstack_top - 1))->func == duk_bi_thread_yield));
69548 DUK_ASSERT_DISABLE(resumee->state != DUK_HTHREAD_STATE_YIELDED ||
69549 (resumee->callstack + resumee->callstack_top - 2)->idx_retval >= 0); /* idx_retval unsigned */
69550 DUK_ASSERT(resumee->state != DUK_HTHREAD_STATE_INACTIVE ||
69551 resumee->callstack_top == 0); /* INACTIVE: no activation, single function value on valstack */
69552
69553 if (thr->heap->lj.iserror) {
69554 /*
69555 * Throw the error in the resumed thread's context; the
69556 * error value is pushed onto the resumee valstack.
69557 *
69558 * Note: the callstack of the target may empty in this case
69559 * too (i.e. the target thread has never been resumed). The
69560 * value stack will contain the initial function in that case,
69561 * which we simply ignore.
69562 */
69563
69564 resumee->resumer = thr;
69565 resumee->state = DUK_HTHREAD_STATE_RUNNING;
69566 thr->state = DUK_HTHREAD_STATE_RESUMED;
69567 DUK_HEAP_SWITCH_THREAD(thr->heap, resumee);
69568 thr = resumee;
69569
69570 thr->heap->lj.type = DUK_LJ_TYPE_THROW;
69571
69572 /* thr->heap->lj.value1 is already the value to throw */
69573 /* thr->heap->lj.value2 is 'thread', will be wiped out at the end */
69574
69575 DUK_ASSERT(thr->heap->lj.iserror); /* already set */
69576
69577 DUK_DD(DUK_DDPRINT("-> resume with an error, converted to a throw in the resumee, propagate"));
69578 goto check_longjmp;
69579 } else if (resumee->state == DUK_HTHREAD_STATE_YIELDED) {
69580 act_idx = resumee->callstack_top - 2; /* Ecmascript function */
69581 DUK_ASSERT_DISABLE(resumee->callstack[act_idx].idx_retval >= 0); /* unsigned */
69582
69583 tv = resumee->valstack + resumee->callstack[act_idx].idx_retval; /* return value from Duktape.Thread.yield() */
69584 DUK_ASSERT(tv >= resumee->valstack && tv < resumee->valstack_top);
69585 tv2 = &thr->heap->lj.value1;
69586 DUK_TVAL_SET_TVAL_UPDREF(thr, tv, tv2); /* side effects */
69587
69588 duk_hthread_callstack_unwind(resumee, act_idx + 1); /* unwind to 'yield' caller */
69589
69590 /* no need to unwind catchstack */
69591
69592 duk__reconfig_valstack_ecma_return(resumee, act_idx);
69593
69594 resumee->resumer = thr;
69595 resumee->state = DUK_HTHREAD_STATE_RUNNING;
69596 thr->state = DUK_HTHREAD_STATE_RESUMED;
69597 DUK_HEAP_SWITCH_THREAD(thr->heap, resumee);
69598#if 0
69599 thr = resumee; /* not needed, as we exit right away */
69600#endif
69601 DUK_DD(DUK_DDPRINT("-> resume with a value, restart execution in resumee"));
69602 retval = DUK__LONGJMP_RESTART;
69603 goto wipe_and_return;
69604 } else {
69605 duk_small_uint_t call_flags;
69606 duk_bool_t setup_rc;
69607
69608 /* resumee: [... initial_func] (currently actually: [initial_func]) */
69609
69610 duk_push_undefined((duk_context *) resumee);
69611 tv = &thr->heap->lj.value1;
69612 duk_push_tval((duk_context *) resumee, tv);
69613
69614 /* resumee: [... initial_func undefined(= this) resume_value ] */
69615
69616 call_flags = DUK_CALL_FLAG_IS_RESUME; /* is resume, not a tail call */
69617
69618 setup_rc = duk_handle_ecma_call_setup(resumee,
69619 1, /* num_stack_args */
69620 call_flags); /* call_flags */
69621 if (setup_rc == 0) {
69622 /* This shouldn't happen; Duktape.Thread.resume()
69623 * should make sure of that. If it does happen
69624 * this internal error will propagate out of the
69625 * executor which can be quite misleading.
69626 */
69627 DUK_ERROR_INTERNAL(thr);
69628 }
69629
69630 resumee->resumer = thr;
69631 resumee->state = DUK_HTHREAD_STATE_RUNNING;
69632 thr->state = DUK_HTHREAD_STATE_RESUMED;
69633 DUK_HEAP_SWITCH_THREAD(thr->heap, resumee);
69634#if 0
69635 thr = resumee; /* not needed, as we exit right away */
69636#endif
69637 DUK_DD(DUK_DDPRINT("-> resume with a value, restart execution in resumee"));
69638 retval = DUK__LONGJMP_RESTART;
69639 goto wipe_and_return;
69640 }
69641 DUK_UNREACHABLE();
69642 break; /* never here */
69643 }
69644
69645 case DUK_LJ_TYPE_YIELD: {
69646 /*
69647 * Currently only allowed only if yielding thread has only
69648 * Ecmascript activations (except for the Duktape.Thread.yield()
69649 * call at the callstack top) and none of them constructor
69650 * calls.
69651 *
69652 * This excludes the 'entry' thread which will always have
69653 * a preventcount > 0.
69654 */
69655
69656 duk_hthread *resumer;
69657
69658 /* duk_bi_duk_object_yield() and duk_bi_duk_object_resume() ensure all of these are met */
69659
69660 DUK_ASSERT(thr != entry_thread); /* Duktape.Thread.yield() should prevent */
69661 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING); /* unchanged from Duktape.Thread.yield() */
69662 DUK_ASSERT(thr->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.yield() activation */
69663 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL &&
69664 DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)) &&
69665 ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1))->func == duk_bi_thread_yield);
69666 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2) != NULL &&
69667 DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2))); /* an Ecmascript function */
69668 DUK_ASSERT_DISABLE((thr->callstack + thr->callstack_top - 2)->idx_retval >= 0); /* unsigned */
69669
69670 resumer = thr->resumer;
69671
69672 DUK_ASSERT(resumer != NULL);
69673 DUK_ASSERT(resumer->state == DUK_HTHREAD_STATE_RESUMED); /* written by a previous RESUME handling */
69674 DUK_ASSERT(resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */
69675 DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 1) != NULL &&
69676 DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 1)) &&
69677 ((duk_hnatfunc *) DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 1))->func == duk_bi_thread_resume);
69678 DUK_ASSERT(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 2) != NULL &&
69679 DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(resumer->callstack + resumer->callstack_top - 2))); /* an Ecmascript function */
69680 DUK_ASSERT_DISABLE((resumer->callstack + resumer->callstack_top - 2)->idx_retval >= 0); /* unsigned */
69681
69682 if (thr->heap->lj.iserror) {
69683 thr->state = DUK_HTHREAD_STATE_YIELDED;
69684 thr->resumer = NULL;
69685 resumer->state = DUK_HTHREAD_STATE_RUNNING;
69686 DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
69687 thr = resumer;
69688
69689 thr->heap->lj.type = DUK_LJ_TYPE_THROW;
69690 /* lj.value1 is already set */
69691 DUK_ASSERT(thr->heap->lj.iserror); /* already set */
69692
69693 DUK_DD(DUK_DDPRINT("-> yield an error, converted to a throw in the resumer, propagate"));
69694 goto check_longjmp;
69695 } else {
69696 duk__handle_yield(thr, resumer, resumer->callstack_top - 2, &thr->heap->lj.value1);
69697
69698 thr->state = DUK_HTHREAD_STATE_YIELDED;
69699 thr->resumer = NULL;
69700 resumer->state = DUK_HTHREAD_STATE_RUNNING;
69701 DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
69702#if 0
69703 thr = resumer; /* not needed, as we exit right away */
69704#endif
69705
69706 DUK_DD(DUK_DDPRINT("-> yield a value, restart execution in resumer"));
69707 retval = DUK__LONGJMP_RESTART;
69708 goto wipe_and_return;
69709 }
69710 DUK_UNREACHABLE();
69711 break; /* never here */
69712 }
69713#endif /* DUK_USE_COROUTINE_SUPPORT */
69714
69715 case DUK_LJ_TYPE_THROW: {
69716 /*
69717 * Three possible outcomes:
69718 * * A try or finally catcher is found => resume there.
69719 * (or)
69720 * * The error propagates to the bytecode executor entry
69721 * level (and we're in the entry thread) => rethrow
69722 * with a new longjmp(), after restoring the previous
69723 * catchpoint.
69724 * * The error is not caught in the current thread, so
69725 * the thread finishes with an error. This works like
69726 * a yielded error, except that the thread is finished
69727 * and can no longer be resumed. (There is always a
69728 * resumer in this case.)
69729 *
69730 * Note: until we hit the entry level, there can only be
69731 * Ecmascript activations.
69732 */
69733
69734 duk_catcher *cat;
69735 duk_hthread *resumer;
69736
69737 cat = thr->catchstack + thr->catchstack_top - 1;
69738 while (cat >= thr->catchstack) {
69739 if (thr == entry_thread &&
69740 cat->callstack_index < entry_callstack_index) {
69741 /* entry level reached */
69742 break;
69743 }
69744
69745 if (DUK_CAT_HAS_CATCH_ENABLED(cat)) {
69746 DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF);
69747
69748 duk__handle_catch(thr,
69749 cat - thr->catchstack,
69750 &thr->heap->lj.value1,
69751 DUK_LJ_TYPE_THROW);
69752
69753 DUK_DD(DUK_DDPRINT("-> throw caught by a 'catch' clause, restart execution"));
69754 retval = DUK__LONGJMP_RESTART;
69755 goto wipe_and_return;
69756 }
69757
69758 if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
69759 DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF);
69760 DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat));
69761
69762 duk__handle_finally(thr,
69763 cat - thr->catchstack,
69764 &thr->heap->lj.value1,
69765 DUK_LJ_TYPE_THROW);
69766
69767 DUK_DD(DUK_DDPRINT("-> throw caught by a 'finally' clause, restart execution"));
69768 retval = DUK__LONGJMP_RESTART;
69769 goto wipe_and_return;
69770 }
69771
69772 cat--;
69773 }
69774
69775 if (thr == entry_thread) {
69776 /* not caught by anything before entry level; rethrow and let the
69777 * final catcher unwind everything
69778 */
69779#if 0
69780 duk_hthread_catchstack_unwind(thr, (cat - thr->catchstack) + 1); /* leave 'cat' as top catcher (also works if catchstack exhausted) */
69781 duk_hthread_callstack_unwind(thr, entry_callstack_index + 1);
69782
69783#endif
69784 DUK_D(DUK_DPRINT("-> throw propagated up to entry level, rethrow and exit bytecode executor"));
69785 retval = DUK__LONGJMP_RETHROW;
69786 goto just_return;
69787 /* Note: MUST NOT wipe_and_return here, as heap->lj must remain intact */
69788 }
69789
69790 DUK_DD(DUK_DDPRINT("-> throw not caught by current thread, yield error to resumer and recheck longjmp"));
69791
69792 /* not caught by current thread, thread terminates (yield error to resumer);
69793 * note that this may cause a cascade if the resumer terminates with an uncaught
69794 * exception etc (this is OK, but needs careful testing)
69795 */
69796
69797 DUK_ASSERT(thr->resumer != NULL);
69798 DUK_ASSERT(thr->resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */
69799 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1) != NULL &&
69800 DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1)) &&
69801 ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */
69802 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2) != NULL &&
69803 DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2))); /* an Ecmascript function */
69804
69805 resumer = thr->resumer;
69806
69807 /* reset longjmp */
69808
69809 DUK_ASSERT(thr->heap->lj.type == DUK_LJ_TYPE_THROW); /* already set */
69810 /* lj.value1 already set */
69811
69812 duk_hthread_terminate(thr); /* updates thread state, minimizes its allocations */
69813 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED);
69814
69815 thr->resumer = NULL;
69816 resumer->state = DUK_HTHREAD_STATE_RUNNING;
69817 DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
69818 thr = resumer;
69819 goto check_longjmp;
69820 }
69821
69822 case DUK_LJ_TYPE_BREAK: /* pseudotypes, not used in actual longjmps */
69823 case DUK_LJ_TYPE_CONTINUE:
69824 case DUK_LJ_TYPE_RETURN:
69825 case DUK_LJ_TYPE_NORMAL:
69826 default: {
69827 /* should never happen, but be robust */
69828 DUK_D(DUK_DPRINT("caught unknown longjmp type %ld, treat as internal error", (long) thr->heap->lj.type));
69829 goto convert_to_internal_error;
69830 }
69831
69832 } /* end switch */
69833
69834 DUK_UNREACHABLE();
69835
69836 wipe_and_return:
69837 /* this is not strictly necessary, but helps debugging */
69838 thr->heap->lj.type = DUK_LJ_TYPE_UNKNOWN;
69839 thr->heap->lj.iserror = 0;
69840
69841 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value1); /* side effects */
69842 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, &thr->heap->lj.value2); /* side effects */
69843
69844 just_return:
69845 return retval;
69846
69847 convert_to_internal_error:
69848 /* This could also be thrown internally (set the error, goto check_longjmp),
69849 * but it's better for internal errors to bubble outwards so that we won't
69850 * infinite loop in this catchpoint.
69851 */
69852 DUK_ERROR_INTERNAL(thr);
69853 DUK_UNREACHABLE();
69854 return retval;
69855}
69856
69857/* Handle a BREAK/CONTINUE opcode. Avoid using longjmp() for BREAK/CONTINUE
69858 * handling because it has a measurable performance impact in ordinary
69859 * environments and an extreme impact in Emscripten (GH-342).
69860 */
69861DUK_LOCAL void duk__handle_break_or_continue(duk_hthread *thr,
69862 duk_uint_t label_id,
69863 duk_small_uint_t lj_type) {
69864 duk_catcher *cat;
69865 duk_size_t orig_callstack_index;
69866
69867 DUK_ASSERT(thr != NULL);
69868
69869 /*
69870 * Find a matching label catcher or 'finally' catcher in
69871 * the same function.
69872 *
69873 * A label catcher must always exist and will match unless
69874 * a 'finally' captures the break/continue first. It is the
69875 * compiler's responsibility to ensure that labels are used
69876 * correctly.
69877 */
69878
69879 /* Note: thr->catchstack_top may be 0, so that cat < thr->catchstack
69880 * initially. This is OK and intended.
69881 */
69882 cat = thr->catchstack + thr->catchstack_top - 1;
69883 DUK_ASSERT(thr->callstack_top > 0);
69884 orig_callstack_index = thr->callstack_top - 1;
69885
69886 DUK_DDD(DUK_DDDPRINT("handling break/continue with label=%ld, callstack index=%ld",
69887 (long) label_id, (long) cat->callstack_index));
69888
69889 while (cat >= thr->catchstack) {
69890 if (cat->callstack_index != orig_callstack_index) {
69891 break;
69892 }
69893 DUK_DDD(DUK_DDDPRINT("considering catcher %ld: type=%ld label=%ld",
69894 (long) (cat - thr->catchstack),
69895 (long) DUK_CAT_GET_TYPE(cat),
69896 (long) DUK_CAT_GET_LABEL(cat)));
69897
69898 if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF &&
69899 DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
69900 duk_size_t cat_idx;
69901 duk_tval tv_tmp;
69902
69903 cat_idx = (duk_size_t) (cat - thr->catchstack); /* get before side effects */
69904
69905 DUK_TVAL_SET_U32(&tv_tmp, (duk_uint32_t) label_id);
69906 duk__handle_finally(thr, cat_idx, &tv_tmp, lj_type);
69907
69908 DUK_DD(DUK_DDPRINT("-> break/continue caught by 'finally', restart execution"));
69909 return;
69910 }
69911 if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_LABEL &&
69912 (duk_uint_t) DUK_CAT_GET_LABEL(cat) == label_id) {
69913 duk_size_t cat_idx;
69914
69915 cat_idx = (duk_size_t) (cat - thr->catchstack);
69916 duk__handle_label(thr, cat_idx, lj_type);
69917
69918 DUK_DD(DUK_DDPRINT("-> break/continue caught by a label catcher (in the same function), restart execution"));
69919 return;
69920 }
69921 cat--;
69922 }
69923
69924 /* should never happen, but be robust */
69925 DUK_D(DUK_DPRINT("-> break/continue not caught by anything in the current function (should never happen), throw internal error"));
69926 DUK_ERROR_INTERNAL(thr);
69927 return;
69928}
69929
69930/* Handle a RETURN opcode. Avoid using longjmp() for return handling because
69931 * it has a measurable performance impact in ordinary environments and an extreme
69932 * impact in Emscripten (GH-342). Return value is on value stack top.
69933 */
69934DUK_LOCAL duk_small_uint_t duk__handle_return(duk_hthread *thr,
69935 duk_hthread *entry_thread,
69936 duk_size_t entry_callstack_top) {
69937 duk_tval *tv1;
69938 duk_tval *tv2;
69939#if defined(DUK_USE_COROUTINE_SUPPORT)
69940 duk_hthread *resumer;
69941#endif
69942 duk_catcher *cat;
69943 duk_size_t new_cat_top;
69944 duk_size_t orig_callstack_index;
69945
69946 /* We can directly access value stack here. */
69947
69948 DUK_ASSERT(thr != NULL);
69949 DUK_ASSERT(entry_thread != NULL);
69950 DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
69951 tv1 = thr->valstack_top - 1;
69952 DUK_TVAL_CHKFAST_INPLACE_FAST(tv1); /* fastint downgrade check for return values */
69953
69954 /*
69955 * Four possible outcomes:
69956 *
69957 * 1. A 'finally' in the same function catches the 'return'.
69958 * It may continue to propagate when 'finally' is finished,
69959 * or it may be neutralized by 'finally' (both handled by
69960 * ENDFIN).
69961 *
69962 * 2. The return happens at the entry level of the bytecode
69963 * executor, so return from the executor (in C stack).
69964 *
69965 * 3. There is a calling (Ecmascript) activation in the call
69966 * stack => return to it, in the same executor instance.
69967 *
69968 * 4. There is no calling activation, and the thread is
69969 * terminated. There is always a resumer in this case,
69970 * which gets the return value similarly to a 'yield'
69971 * (except that the current thread can no longer be
69972 * resumed).
69973 */
69974
69975 DUK_ASSERT(thr != NULL);
69976 DUK_ASSERT(thr->callstack_top >= 1);
69977 DUK_ASSERT(thr->catchstack != NULL);
69978
69979 /* XXX: does not work if thr->catchstack is NULL */
69980 /* XXX: does not work if thr->catchstack is allocated but lowest pointer */
69981
69982 cat = thr->catchstack + thr->catchstack_top - 1; /* may be < thr->catchstack initially */
69983 DUK_ASSERT(thr->callstack_top > 0); /* ensures callstack_top - 1 >= 0 */
69984 orig_callstack_index = thr->callstack_top - 1;
69985
69986 while (cat >= thr->catchstack) {
69987 if (cat->callstack_index != orig_callstack_index) {
69988 break;
69989 }
69990 if (DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_TCF &&
69991 DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
69992 duk_size_t cat_idx;
69993
69994 cat_idx = (duk_size_t) (cat - thr->catchstack); /* get before side effects */
69995
69996 DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
69997 duk__handle_finally(thr, cat_idx, thr->valstack_top - 1, DUK_LJ_TYPE_RETURN);
69998
69999 DUK_DD(DUK_DDPRINT("-> return caught by 'finally', restart execution"));
70000 return DUK__RETHAND_RESTART;
70001 }
70002 cat--;
70003 }
70004 /* If out of catchstack, cat = thr->catchstack - 1;
70005 * new_cat_top will be 0 in that case.
70006 */
70007 new_cat_top = (duk_size_t) ((cat + 1) - thr->catchstack);
70008 cat = NULL; /* avoid referencing, invalidated */
70009
70010 DUK_DDD(DUK_DDDPRINT("no catcher in catch stack, return to calling activation / yield"));
70011
70012 if (thr == entry_thread &&
70013 thr->callstack_top == entry_callstack_top) {
70014 /* Return to the bytecode executor caller which will unwind stacks.
70015 * Return value is already on the stack top: [ ... retval ].
70016 */
70017
70018 /* XXX: could unwind catchstack here, so that call handling
70019 * didn't need to do that?
70020 */
70021 DUK_DDD(DUK_DDDPRINT("-> return propagated up to entry level, exit bytecode executor"));
70022 return DUK__RETHAND_FINISHED;
70023 }
70024
70025 if (thr->callstack_top >= 2) {
70026 /* There is a caller; it MUST be an Ecmascript caller (otherwise it would
70027 * match entry level check)
70028 */
70029
70030 DUK_DDD(DUK_DDDPRINT("return to Ecmascript caller, idx_retval=%ld, lj_value1=%!T",
70031 (long) (thr->callstack + thr->callstack_top - 2)->idx_retval,
70032 (duk_tval *) &thr->heap->lj.value1));
70033
70034 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 2))); /* must be ecmascript */
70035
70036 tv1 = thr->valstack + (thr->callstack + thr->callstack_top - 2)->idx_retval;
70037 DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
70038 tv2 = thr->valstack_top - 1;
70039 DUK_TVAL_SET_TVAL_UPDREF(thr, tv1, tv2); /* side effects */
70040
70041 DUK_DDD(DUK_DDDPRINT("return value at idx_retval=%ld is %!T",
70042 (long) (thr->callstack + thr->callstack_top - 2)->idx_retval,
70043 (duk_tval *) (thr->valstack + (thr->callstack + thr->callstack_top - 2)->idx_retval)));
70044
70045 duk_hthread_catchstack_unwind(thr, new_cat_top); /* leave 'cat' as top catcher (also works if catchstack exhausted) */
70046 duk_hthread_callstack_unwind(thr, thr->callstack_top - 1);
70047 duk__reconfig_valstack_ecma_return(thr, thr->callstack_top - 1);
70048
70049 DUK_DD(DUK_DDPRINT("-> return not intercepted, restart execution in caller"));
70050 return DUK__RETHAND_RESTART;
70051 }
70052
70053#if defined(DUK_USE_COROUTINE_SUPPORT)
70054 DUK_DD(DUK_DDPRINT("no calling activation, thread finishes (similar to yield)"));
70055
70056 DUK_ASSERT(thr->resumer != NULL);
70057 DUK_ASSERT(thr->resumer->callstack_top >= 2); /* Ecmascript activation + Duktape.Thread.resume() activation */
70058 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1) != NULL &&
70059 DUK_HOBJECT_IS_NATFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1)) &&
70060 ((duk_hnatfunc *) DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 1))->func == duk_bi_thread_resume); /* Duktape.Thread.resume() */
70061 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2) != NULL &&
70062 DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->resumer->callstack + thr->resumer->callstack_top - 2))); /* an Ecmascript function */
70063 DUK_ASSERT_DISABLE((thr->resumer->callstack + thr->resumer->callstack_top - 2)->idx_retval >= 0); /* unsigned */
70064 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_RUNNING);
70065 DUK_ASSERT(thr->resumer->state == DUK_HTHREAD_STATE_RESUMED);
70066
70067 resumer = thr->resumer;
70068
70069 /* Share yield longjmp handler. */
70070 DUK_ASSERT(thr->valstack_top - 1 >= thr->valstack_bottom);
70071 duk__handle_yield(thr, resumer, resumer->callstack_top - 2, thr->valstack_top - 1);
70072
70073 duk_hthread_terminate(thr); /* updates thread state, minimizes its allocations */
70074 DUK_ASSERT(thr->state == DUK_HTHREAD_STATE_TERMINATED);
70075
70076 thr->resumer = NULL;
70077 resumer->state = DUK_HTHREAD_STATE_RUNNING;
70078 DUK_HEAP_SWITCH_THREAD(thr->heap, resumer);
70079#if 0
70080 thr = resumer; /* not needed */
70081#endif
70082
70083 DUK_DD(DUK_DDPRINT("-> return not caught, thread terminated; handle like yield, restart execution in resumer"));
70084 return DUK__RETHAND_RESTART;
70085#else
70086 /* Without coroutine support this case should never happen. */
70087 DUK_ERROR_INTERNAL(thr);
70088 return DUK__RETHAND_FINISHED; /* not executed */
70089#endif
70090}
70091
70092/*
70093 * Executor interrupt handling
70094 *
70095 * The handler is called whenever the interrupt countdown reaches zero
70096 * (or below). The handler must perform whatever checks are activated,
70097 * e.g. check for cumulative step count to impose an execution step
70098 * limit or check for breakpoints or other debugger interaction.
70099 *
70100 * When the actions are done, the handler must reinit the interrupt
70101 * init and counter values. The 'init' value must indicate how many
70102 * bytecode instructions are executed before the next interrupt. The
70103 * counter must interface with the bytecode executor loop. Concretely,
70104 * the new init value is normally one higher than the new counter value.
70105 * For instance, to execute exactly one bytecode instruction the init
70106 * value is set to 1 and the counter to 0. If an error is thrown by the
70107 * interrupt handler, the counters are set to the same value (e.g. both
70108 * to 0 to cause an interrupt when the next bytecode instruction is about
70109 * to be executed after error handling).
70110 *
70111 * Maintaining the init/counter value properly is important for accurate
70112 * behavior. For instance, executor step limit needs a cumulative step
70113 * count which is simply computed as a sum of 'init' values. This must
70114 * work accurately even when single stepping.
70115 */
70116
70117#if defined(DUK_USE_INTERRUPT_COUNTER)
70118
70119#define DUK__INT_NOACTION 0 /* no specific action, resume normal execution */
70120#define DUK__INT_RESTART 1 /* must "goto restart_execution", e.g. breakpoints changed */
70121
70122#if defined(DUK_USE_DEBUGGER_SUPPORT)
70123DUK_LOCAL void duk__interrupt_handle_debugger(duk_hthread *thr, duk_bool_t *out_immediate, duk_small_uint_t *out_interrupt_retval) {
70124 duk_context *ctx;
70125 duk_activation *act;
70126 duk_breakpoint *bp;
70127 duk_breakpoint **bp_active;
70128 duk_uint_fast32_t line = 0;
70129 duk_bool_t process_messages;
70130 duk_bool_t processed_messages = 0;
70131
70132 DUK_ASSERT(thr->heap->dbg_processing == 0); /* don't re-enter e.g. during Eval */
70133
70134 ctx = (duk_context *) thr;
70135 act = thr->callstack + thr->callstack_top - 1;
70136
70137 /* It might seem that replacing 'thr->heap' with just 'heap' below
70138 * might be a good idea, but it increases code size slightly
70139 * (probably due to unnecessary spilling) at least on x64.
70140 */
70141
70142 /*
70143 * Breakpoint and step state checks
70144 */
70145
70146 if (act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE ||
70147 (thr->heap->dbg_step_thread == thr &&
70148 thr->heap->dbg_step_csindex == thr->callstack_top - 1)) {
70149 line = duk_debug_curr_line(thr);
70150
70151 if (act->prev_line != line) {
70152 /* Stepped? Step out is handled by callstack unwind. */
70153 if ((thr->heap->dbg_step_type == DUK_STEP_TYPE_INTO ||
70154 thr->heap->dbg_step_type == DUK_STEP_TYPE_OVER) &&
70155 (thr->heap->dbg_step_thread == thr) &&
70156 (thr->heap->dbg_step_csindex == thr->callstack_top - 1) &&
70157 (line != thr->heap->dbg_step_startline)) {
70158 DUK_D(DUK_DPRINT("STEP STATE TRIGGERED PAUSE at line %ld",
70159 (long) line));
70160
70161 DUK_HEAP_SET_PAUSED(thr->heap);
70162 }
70163
70164 /* Check for breakpoints only on line transition.
70165 * Breakpoint is triggered when we enter the target
70166 * line from a different line, and the previous line
70167 * was within the same function.
70168 *
70169 * This condition is tricky: the condition used to be
70170 * that transition to -or across- the breakpoint line
70171 * triggered the breakpoint. This seems intuitively
70172 * better because it handles breakpoints on lines with
70173 * no emitted opcodes; but this leads to the issue
70174 * described in: https://github.com/svaarala/duktape/issues/263.
70175 */
70176 bp_active = thr->heap->dbg_breakpoints_active;
70177 for (;;) {
70178 bp = *bp_active++;
70179 if (bp == NULL) {
70180 break;
70181 }
70182
70183 DUK_ASSERT(bp->filename != NULL);
70184 if (act->prev_line != bp->line && line == bp->line) {
70185 DUK_D(DUK_DPRINT("BREAKPOINT TRIGGERED at %!O:%ld",
70186 (duk_heaphdr *) bp->filename, (long) bp->line));
70187
70188 DUK_HEAP_SET_PAUSED(thr->heap);
70189 }
70190 }
70191 } else {
70192 ;
70193 }
70194
70195 act->prev_line = line;
70196 }
70197
70198 /*
70199 * Rate limit check for sending status update or peeking into
70200 * the debug transport. Both can be expensive operations that
70201 * we don't want to do on every opcode.
70202 *
70203 * Making sure the interval remains reasonable on a wide variety
70204 * of targets and bytecode is difficult without a timestamp, so
70205 * we use a Date-provided timestamp for the rate limit check.
70206 * But since it's also expensive to get a timestamp, a bytecode
70207 * counter is used to rate limit getting timestamps.
70208 */
70209
70210 process_messages = 0;
70211 if (thr->heap->dbg_state_dirty || DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) || thr->heap->dbg_detaching) {
70212 /* Enter message processing loop for sending Status notifys and
70213 * to finish a pending detach.
70214 */
70215 process_messages = 1;
70216 }
70217
70218 /* XXX: remove heap->dbg_exec_counter, use heap->inst_count_interrupt instead? */
70219 thr->heap->dbg_exec_counter += thr->interrupt_init;
70220 if (thr->heap->dbg_exec_counter - thr->heap->dbg_last_counter >= DUK_HEAP_DBG_RATELIMIT_OPCODES) {
70221 /* Overflow of the execution counter is fine and doesn't break
70222 * anything here.
70223 */
70224
70225 duk_double_t now, diff_last;
70226
70227 thr->heap->dbg_last_counter = thr->heap->dbg_exec_counter;
70228 now = DUK_USE_DATE_GET_NOW(ctx);
70229
70230 diff_last = now - thr->heap->dbg_last_time;
70231 if (diff_last < 0.0 || diff_last >= (duk_double_t) DUK_HEAP_DBG_RATELIMIT_MILLISECS) {
70232 /* Negative value checked so that a "time jump" works
70233 * reasonably.
70234 *
70235 * Same interval is now used for status sending and
70236 * peeking.
70237 */
70238
70239 thr->heap->dbg_last_time = now;
70240 thr->heap->dbg_state_dirty = 1;
70241 process_messages = 1;
70242 }
70243 }
70244
70245 /*
70246 * Process messages and send status if necessary.
70247 *
70248 * If we're paused, we'll block for new messages. If we're not
70249 * paused, we'll process anything we can peek but won't block
70250 * for more. Detach (and re-attach) handling is all localized
70251 * to duk_debug_process_messages() too.
70252 *
70253 * Debugger writes outside the message loop may cause debugger
70254 * detach1 phase to run, after which dbg_read_cb == NULL and
70255 * dbg_detaching != 0. The message loop will finish the detach
70256 * by running detach2 phase, so enter the message loop also when
70257 * detaching.
70258 */
70259
70260 act = NULL; /* may be changed */
70261 if (process_messages) {
70262 DUK_ASSERT(thr->heap->dbg_processing == 0);
70263 processed_messages = duk_debug_process_messages(thr, 0 /*no_block*/);
70264 DUK_ASSERT(thr->heap->dbg_processing == 0);
70265 }
70266
70267 /* Continue checked execution if there are breakpoints or we're stepping.
70268 * Also use checked execution if paused flag is active - it shouldn't be
70269 * because the debug message loop shouldn't terminate if it was. Step out
70270 * is handled by callstack unwind and doesn't need checked execution.
70271 * Note that debugger may have detached due to error or explicit request
70272 * above, so we must recheck attach status.
70273 */
70274
70275 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
70276 act = thr->callstack + thr->callstack_top - 1; /* relookup, may have changed */
70277 if (act->flags & DUK_ACT_FLAG_BREAKPOINT_ACTIVE ||
70278 ((thr->heap->dbg_step_type == DUK_STEP_TYPE_INTO ||
70279 thr->heap->dbg_step_type == DUK_STEP_TYPE_OVER) &&
70280 thr->heap->dbg_step_thread == thr &&
70281 thr->heap->dbg_step_csindex == thr->callstack_top - 1) ||
70282 DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap)) {
70283 *out_immediate = 1;
70284 }
70285
70286 /* If we processed any debug messages breakpoints may have
70287 * changed; restart execution to re-check active breakpoints.
70288 */
70289 if (processed_messages) {
70290 DUK_D(DUK_DPRINT("processed debug messages, restart execution to recheck possibly changed breakpoints"));
70291 *out_interrupt_retval = DUK__INT_RESTART;
70292 }
70293 } else {
70294 DUK_D(DUK_DPRINT("debugger became detached, resume normal execution"));
70295 }
70296}
70297#endif /* DUK_USE_DEBUGGER_SUPPORT */
70298
70299DUK_LOCAL duk_small_uint_t duk__executor_interrupt(duk_hthread *thr) {
70300 duk_int_t ctr;
70301 duk_activation *act;
70302 duk_hcompfunc *fun;
70303 duk_bool_t immediate = 0;
70304 duk_small_uint_t retval;
70305
70306 DUK_ASSERT(thr != NULL);
70307 DUK_ASSERT(thr->heap != NULL);
70308 DUK_ASSERT(thr->callstack != NULL);
70309 DUK_ASSERT(thr->callstack_top > 0);
70310
70311#if defined(DUK_USE_DEBUG)
70312 thr->heap->inst_count_interrupt += thr->interrupt_init;
70313 DUK_DD(DUK_DDPRINT("execution interrupt, counter=%ld, init=%ld, "
70314 "instruction counts: executor=%ld, interrupt=%ld",
70315 (long) thr->interrupt_counter, (long) thr->interrupt_init,
70316 (long) thr->heap->inst_count_exec, (long) thr->heap->inst_count_interrupt));
70317#endif
70318
70319 retval = DUK__INT_NOACTION;
70320 ctr = DUK_HTHREAD_INTCTR_DEFAULT;
70321
70322 /*
70323 * Avoid nested calls. Concretely this happens during debugging, e.g.
70324 * when we eval() an expression.
70325 *
70326 * Also don't interrupt if we're currently doing debug processing
70327 * (which can be initiated outside the bytecode executor) as this
70328 * may cause the debugger to be called recursively. Check required
70329 * for correct operation of throw intercept and other "exotic" halting
70330 * scenarios.
70331 */
70332
70333#if defined(DUK_USE_DEBUGGER_SUPPORT)
70334 if (DUK_HEAP_HAS_INTERRUPT_RUNNING(thr->heap) || thr->heap->dbg_processing) {
70335#else
70336 if (DUK_HEAP_HAS_INTERRUPT_RUNNING(thr->heap)) {
70337#endif
70338 DUK_DD(DUK_DDPRINT("nested executor interrupt, ignoring"));
70339
70340 /* Set a high interrupt counter; the original executor
70341 * interrupt invocation will rewrite before exiting.
70342 */
70343 thr->interrupt_init = ctr;
70344 thr->interrupt_counter = ctr - 1;
70345 return DUK__INT_NOACTION;
70346 }
70347 DUK_HEAP_SET_INTERRUPT_RUNNING(thr->heap);
70348
70349 act = thr->callstack + thr->callstack_top - 1;
70350
70351 fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
70352 DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC((duk_hobject *) fun));
70353
70354 DUK_UNREF(fun);
70355
70356#if defined(DUK_USE_EXEC_TIMEOUT_CHECK)
70357 /*
70358 * Execution timeout check
70359 */
70360
70361 if (DUK_USE_EXEC_TIMEOUT_CHECK(thr->heap->heap_udata)) {
70362 /* Keep throwing an error whenever we get here. The unusual values
70363 * are set this way because no instruction is ever executed, we just
70364 * throw an error until all try/catch/finally and other catchpoints
70365 * have been exhausted. Duktape/C code gets control at each protected
70366 * call but whenever it enters back into Duktape the RangeError gets
70367 * raised. User exec timeout check must consistently indicate a timeout
70368 * until we've fully bubbled out of Duktape.
70369 */
70370 DUK_D(DUK_DPRINT("execution timeout, throwing a RangeError"));
70371 thr->interrupt_init = 0;
70372 thr->interrupt_counter = 0;
70373 DUK_HEAP_CLEAR_INTERRUPT_RUNNING(thr->heap);
70374 DUK_ERROR_RANGE(thr, "execution timeout");
70375 }
70376#endif /* DUK_USE_EXEC_TIMEOUT_CHECK */
70377
70378#if defined(DUK_USE_DEBUGGER_SUPPORT)
70379 if (!thr->heap->dbg_processing &&
70380 (thr->heap->dbg_read_cb != NULL || thr->heap->dbg_detaching)) {
70381 /* Avoid recursive re-entry; enter when we're attached or
70382 * detaching (to finish off the pending detach).
70383 */
70384 duk__interrupt_handle_debugger(thr, &immediate, &retval);
70385 act = thr->callstack + thr->callstack_top - 1; /* relookup if changed */
70386 DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */
70387 }
70388#endif /* DUK_USE_DEBUGGER_SUPPORT */
70389
70390 /*
70391 * Update the interrupt counter
70392 */
70393
70394 if (immediate) {
70395 /* Cause an interrupt after executing one instruction. */
70396 ctr = 1;
70397 }
70398
70399 /* The counter value is one less than the init value: init value should
70400 * indicate how many instructions are executed before interrupt. To
70401 * execute 1 instruction (after interrupt handler return), counter must
70402 * be 0.
70403 */
70404 DUK_ASSERT(ctr >= 1);
70405 thr->interrupt_init = ctr;
70406 thr->interrupt_counter = ctr - 1;
70407 DUK_HEAP_CLEAR_INTERRUPT_RUNNING(thr->heap);
70408
70409 return retval;
70410}
70411#endif /* DUK_USE_INTERRUPT_COUNTER */
70412
70413/*
70414 * Debugger handling for executor restart
70415 *
70416 * Check for breakpoints, stepping, etc, and figure out if we should execute
70417 * in checked or normal mode. Note that we can't do this when an activation
70418 * is created, because breakpoint status (and stepping status) may change
70419 * later, so we must recheck every time we're executing an activation.
70420 * This primitive should be side effect free to avoid changes during check.
70421 */
70422
70423#if defined(DUK_USE_DEBUGGER_SUPPORT)
70424DUK_LOCAL void duk__executor_recheck_debugger(duk_hthread *thr, duk_activation *act, duk_hcompfunc *fun) {
70425 duk_heap *heap;
70426 duk_tval *tv_tmp;
70427 duk_hstring *filename;
70428 duk_small_uint_t bp_idx;
70429 duk_breakpoint **bp_active;
70430
70431 DUK_ASSERT(thr != NULL);
70432 DUK_ASSERT(act != NULL);
70433 DUK_ASSERT(fun != NULL);
70434
70435 heap = thr->heap;
70436 bp_active = heap->dbg_breakpoints_active;
70437 act->flags &= ~DUK_ACT_FLAG_BREAKPOINT_ACTIVE;
70438
70439 tv_tmp = duk_hobject_find_existing_entry_tval_ptr(thr->heap, (duk_hobject *) fun, DUK_HTHREAD_STRING_FILE_NAME(thr));
70440 if (tv_tmp && DUK_TVAL_IS_STRING(tv_tmp)) {
70441 filename = DUK_TVAL_GET_STRING(tv_tmp);
70442
70443 /* Figure out all active breakpoints. A breakpoint is
70444 * considered active if the current function's fileName
70445 * matches the breakpoint's fileName, AND there is no
70446 * inner function that has matching line numbers
70447 * (otherwise a breakpoint would be triggered both
70448 * inside and outside of the inner function which would
70449 * be confusing). Example:
70450 *
70451 * function foo() {
70452 * print('foo');
70453 * function bar() { <-. breakpoints in these
70454 * print('bar'); | lines should not affect
70455 * } <-' foo() execution
70456 * bar();
70457 * }
70458 *
70459 * We need a few things that are only available when
70460 * debugger support is enabled: (1) a line range for
70461 * each function, and (2) access to the function
70462 * template to access the inner functions (and their
70463 * line ranges).
70464 *
70465 * It's important to have a narrow match for active
70466 * breakpoints so that we don't enter checked execution
70467 * when that's not necessary. For instance, if we're
70468 * running inside a certain function and there's
70469 * breakpoint outside in (after the call site), we
70470 * don't want to slow down execution of the function.
70471 */
70472
70473 for (bp_idx = 0; bp_idx < heap->dbg_breakpoint_count; bp_idx++) {
70474 duk_breakpoint *bp = heap->dbg_breakpoints + bp_idx;
70475 duk_hobject **funcs, **funcs_end;
70476 duk_hcompfunc *inner_fun;
70477 duk_bool_t bp_match;
70478
70479 if (bp->filename == filename &&
70480 bp->line >= fun->start_line && bp->line <= fun->end_line) {
70481 bp_match = 1;
70482 DUK_DD(DUK_DDPRINT("breakpoint filename and line match: "
70483 "%s:%ld vs. %s (line %ld vs. %ld-%ld)",
70484 DUK_HSTRING_GET_DATA(bp->filename),
70485 (long) bp->line,
70486 DUK_HSTRING_GET_DATA(filename),
70487 (long) bp->line,
70488 (long) fun->start_line,
70489 (long) fun->end_line));
70490
70491 funcs = DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, fun);
70492 funcs_end = DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, fun);
70493 while (funcs != funcs_end) {
70494 inner_fun = (duk_hcompfunc *) *funcs;
70495 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) inner_fun));
70496 if (bp->line >= inner_fun->start_line && bp->line <= inner_fun->end_line) {
70497 DUK_DD(DUK_DDPRINT("inner function masks ('captures') breakpoint"));
70498 bp_match = 0;
70499 break;
70500 }
70501 funcs++;
70502 }
70503
70504 if (bp_match) {
70505 /* No need to check for size of bp_active list,
70506 * it's always larger than maximum number of
70507 * breakpoints.
70508 */
70509 act->flags |= DUK_ACT_FLAG_BREAKPOINT_ACTIVE;
70510 *bp_active = heap->dbg_breakpoints + bp_idx;
70511 bp_active++;
70512 }
70513 }
70514 }
70515 }
70516
70517 *bp_active = NULL; /* terminate */
70518
70519 DUK_DD(DUK_DDPRINT("ACTIVE BREAKPOINTS: %ld", (long) (bp_active - thr->heap->dbg_breakpoints_active)));
70520
70521 /* Force pause if we were doing "step into" in another activation. */
70522 if (thr->heap->dbg_step_thread != NULL &&
70523 thr->heap->dbg_step_type == DUK_STEP_TYPE_INTO &&
70524 (thr->heap->dbg_step_thread != thr ||
70525 thr->heap->dbg_step_csindex != thr->callstack_top - 1)) {
70526 DUK_D(DUK_DPRINT("STEP INTO ACTIVE, FORCE PAUSED"));
70527 DUK_HEAP_SET_PAUSED(thr->heap);
70528 }
70529
70530 /* Force interrupt right away if we're paused or in "checked mode".
70531 * Step out is handled by callstack unwind.
70532 */
70533 if (act->flags & (DUK_ACT_FLAG_BREAKPOINT_ACTIVE) ||
70534 DUK_HEAP_HAS_DEBUGGER_PAUSED(thr->heap) ||
70535 (thr->heap->dbg_step_type != DUK_STEP_TYPE_OUT &&
70536 thr->heap->dbg_step_csindex == thr->callstack_top - 1)) {
70537 /* We'll need to interrupt early so recompute the init
70538 * counter to reflect the number of bytecode instructions
70539 * executed so that step counts for e.g. debugger rate
70540 * limiting are accurate.
70541 */
70542 DUK_ASSERT(thr->interrupt_counter <= thr->interrupt_init);
70543 thr->interrupt_init = thr->interrupt_init - thr->interrupt_counter;
70544 thr->interrupt_counter = 0;
70545 }
70546}
70547#endif /* DUK_USE_DEBUGGER_SUPPORT */
70548
70549/*
70550 * Ecmascript bytecode executor.
70551 *
70552 * Resume execution for the current thread from its current activation.
70553 * Returns when execution would return from the entry level activation,
70554 * leaving a single return value on top of the stack. Function calls
70555 * and thread resumptions are handled internally. If an error occurs,
70556 * a longjmp() with type DUK_LJ_TYPE_THROW is called on the entry level
70557 * setjmp() jmpbuf.
70558 *
70559 * Ecmascript function calls and coroutine resumptions are handled
70560 * internally (by the outer executor function) without recursive C calls.
70561 * Other function calls are handled using duk_handle_call(), increasing
70562 * C recursion depth.
70563 *
70564 * Abrupt completions (= long control tranfers) are handled either
70565 * directly by reconfiguring relevant stacks and restarting execution,
70566 * or via a longjmp. Longjmp-free handling is preferable for performance
70567 * (especially Emscripten performance), and is used for: break, continue,
70568 * and return.
70569 *
70570 * For more detailed notes, see doc/execution.rst.
70571 *
70572 * Also see doc/code-issues.rst for discussion of setjmp(), longjmp(),
70573 * and volatile.
70574 */
70575
70576/* Presence of 'fun' is config based, there's a marginal performance
70577 * difference and the best option is architecture dependent.
70578 */
70579#if defined(DUK_USE_EXEC_FUN_LOCAL)
70580#define DUK__FUN() fun
70581#else
70582#define DUK__FUN() ((duk_hcompfunc *) DUK_ACT_GET_FUNC((thr)->callstack + (thr)->callstack_top - 1))
70583#endif
70584#define DUK__STRICT() (DUK_HOBJECT_HAS_STRICT((duk_hobject *) DUK__FUN()))
70585
70586/* Reg/const access macros: these are very footprint and performance sensitive
70587 * so modify with care. Arguments are sometimes evaluated multiple times which
70588 * is not ideal.
70589 */
70590#define DUK__REG(x) (*(thr->valstack_bottom + (x)))
70591#define DUK__REGP(x) (thr->valstack_bottom + (x))
70592#define DUK__CONST(x) (*(consts + (x)))
70593#define DUK__CONSTP(x) (consts + (x))
70594
70595/* Reg/const access macros which take the 32-bit instruction and avoid an
70596 * explicit field decoding step by using shifts and masks. These must be
70597 * kept in sync with duk_js_bytecode.h. The shift/mask values are chosen
70598 * so that 'ins' can be shifted and masked and used as a -byte- offset
70599 * instead of a duk_tval offset which needs further shifting (which is an
70600 * issue on some, but not all, CPUs).
70601 */
70602#define DUK__RCBIT_B DUK_BC_REGCONST_B
70603#define DUK__RCBIT_C DUK_BC_REGCONST_C
70604#if defined(DUK_USE_EXEC_REGCONST_OPTIMIZE)
70605#if defined(DUK_USE_PACKED_TVAL)
70606#define DUK__TVAL_SHIFT 3 /* sizeof(duk_tval) == 8 */
70607#else
70608#define DUK__TVAL_SHIFT 4 /* sizeof(duk_tval) == 16; not always the case so also asserted for */
70609#endif
70610#define DUK__SHIFT_A (DUK_BC_SHIFT_A - DUK__TVAL_SHIFT)
70611#define DUK__SHIFT_B (DUK_BC_SHIFT_B - DUK__TVAL_SHIFT)
70612#define DUK__SHIFT_C (DUK_BC_SHIFT_C - DUK__TVAL_SHIFT)
70613#define DUK__SHIFT_BC (DUK_BC_SHIFT_BC - DUK__TVAL_SHIFT)
70614#define DUK__MASK_A (DUK_BC_UNSHIFTED_MASK_A << DUK__TVAL_SHIFT)
70615#define DUK__MASK_B (DUK_BC_UNSHIFTED_MASK_B << DUK__TVAL_SHIFT)
70616#define DUK__MASK_C (DUK_BC_UNSHIFTED_MASK_C << DUK__TVAL_SHIFT)
70617#define DUK__MASK_BC (DUK_BC_UNSHIFTED_MASK_BC << DUK__TVAL_SHIFT)
70618#define DUK__BYTEOFF_A(ins) (((ins) >> DUK__SHIFT_A) & DUK__MASK_A)
70619#define DUK__BYTEOFF_B(ins) (((ins) >> DUK__SHIFT_B) & DUK__MASK_B)
70620#define DUK__BYTEOFF_C(ins) (((ins) >> DUK__SHIFT_C) & DUK__MASK_C)
70621#define DUK__BYTEOFF_BC(ins) (((ins) >> DUK__SHIFT_BC) & DUK__MASK_BC)
70622
70623#define DUK__REGP_A(ins) ((duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + DUK__BYTEOFF_A((ins))))
70624#define DUK__REGP_B(ins) ((duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + DUK__BYTEOFF_B((ins))))
70625#define DUK__REGP_C(ins) ((duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + DUK__BYTEOFF_C((ins))))
70626#define DUK__REGP_BC(ins) ((duk_tval *) (void *) ((duk_uint8_t *) thr->valstack_bottom + DUK__BYTEOFF_BC((ins))))
70627#define DUK__CONSTP_A(ins) ((duk_tval *) (void *) ((duk_uint8_t *) consts + DUK__BYTEOFF_A((ins))))
70628#define DUK__CONSTP_B(ins) ((duk_tval *) (void *) ((duk_uint8_t *) consts + DUK__BYTEOFF_B((ins))))
70629#define DUK__CONSTP_C(ins) ((duk_tval *) (void *) ((duk_uint8_t *) consts + DUK__BYTEOFF_C((ins))))
70630#define DUK__CONSTP_BC(ins) ((duk_tval *) (void *) ((duk_uint8_t *) consts + DUK__BYTEOFF_BC((ins))))
70631#define DUK__REGCONSTP_B(ins) ((duk_tval *) (void *) ((duk_uint8_t *) (((ins) & DUK__RCBIT_B) ? consts : thr->valstack_bottom) + DUK__BYTEOFF_B((ins))))
70632#define DUK__REGCONSTP_C(ins) ((duk_tval *) (void *) ((duk_uint8_t *) (((ins) & DUK__RCBIT_C) ? consts : thr->valstack_bottom) + DUK__BYTEOFF_C((ins))))
70633#else /* DUK_USE_EXEC_REGCONST_OPTIMIZE */
70634/* Safe alternatives, no assumption about duk_tval size. */
70635#define DUK__REGP_A(ins) DUK__REGP(DUK_DEC_A((ins)))
70636#define DUK__REGP_B(ins) DUK__REGP(DUK_DEC_B((ins)))
70637#define DUK__REGP_C(ins) DUK__REGP(DUK_DEC_C((ins)))
70638#define DUK__REGP_BC(ins) DUK__REGP(DUK_DEC_BC((ins)))
70639#define DUK__CONSTP_A(ins) DUK__CONSTP(DUK_DEC_A((ins)))
70640#define DUK__CONSTP_B(ins) DUK__CONSTP(DUK_DEC_B((ins)))
70641#define DUK__CONSTP_C(ins) DUK__CONSTP(DUK_DEC_C((ins)))
70642#define DUK__CONSTP_BC(ins) DUK__CONSTP(DUK_DEC_BC((ins)))
70643#define DUK__REGCONSTP_B(ins) ((((ins) & DUK__RCBIT_B) ? consts : thr->valstack_bottom) + DUK_DEC_B((ins)))
70644#define DUK__REGCONSTP_C(ins) ((((ins) & DUK__RCBIT_C) ? consts : thr->valstack_bottom) + DUK_DEC_C((ins)))
70645#endif /* DUK_USE_EXEC_REGCONST_OPTIMIZE */
70646
70647#if defined(DUK_USE_VERBOSE_EXECUTOR_ERRORS)
70648#define DUK__INTERNAL_ERROR(msg) do { \
70649 DUK_ERROR_ERROR(thr, (msg)); \
70650 } while (0)
70651#else
70652#define DUK__INTERNAL_ERROR(msg) do { \
70653 goto internal_error; \
70654 } while (0)
70655#endif
70656
70657#define DUK__SYNC_CURR_PC() do { \
70658 duk_activation *act; \
70659 act = thr->callstack + thr->callstack_top - 1; \
70660 act->curr_pc = curr_pc; \
70661 } while (0)
70662#define DUK__SYNC_AND_NULL_CURR_PC() do { \
70663 duk_activation *act; \
70664 act = thr->callstack + thr->callstack_top - 1; \
70665 act->curr_pc = curr_pc; \
70666 thr->ptr_curr_pc = NULL; \
70667 } while (0)
70668
70669#if defined(DUK_USE_EXEC_PREFER_SIZE)
70670#define DUK__LOOKUP_INDIRECT_INDEX(idx) do { \
70671 (idx) = (duk_uint_fast_t) duk_get_uint(ctx, (idx)); \
70672 } while (0)
70673#elif defined(DUK_USE_FASTINT)
70674#define DUK__LOOKUP_INDIRECT_INDEX(idx) do { \
70675 duk_tval *tv_ind; \
70676 tv_ind = DUK__REGP((idx)); \
70677 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind)); \
70678 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv_ind)); /* compiler guarantees */ \
70679 (idx) = (duk_uint_fast_t) DUK_TVAL_GET_FASTINT_U32(tv_ind); \
70680 } while (0)
70681#else
70682#define DUK__LOOKUP_INDIRECT_INDEX(idx) do { \
70683 duk_tval *tv_ind; \
70684 tv_ind = DUK__REGP(idx); \
70685 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_ind)); \
70686 idx = (duk_uint_fast_t) DUK_TVAL_GET_NUMBER(tv_ind); \
70687 } while (0)
70688#endif
70689
70690DUK_LOCAL void duk__handle_executor_error(duk_heap *heap,
70691 duk_hthread *entry_thread,
70692 duk_size_t entry_callstack_top,
70693 duk_int_t entry_call_recursion_depth,
70694 duk_jmpbuf *entry_jmpbuf_ptr) {
70695 duk_small_uint_t lj_ret;
70696
70697 /* Longjmp callers are required to sync-and-null thr->ptr_curr_pc
70698 * before longjmp.
70699 */
70700 DUK_ASSERT(heap->curr_thread != NULL);
70701 DUK_ASSERT(heap->curr_thread->ptr_curr_pc == NULL);
70702
70703 /* XXX: signalling the need to shrink check (only if unwound) */
70704
70705 /* Must be restored here to handle e.g. yields properly. */
70706 heap->call_recursion_depth = entry_call_recursion_depth;
70707
70708 /* Switch to caller's setjmp() catcher so that if an error occurs
70709 * during error handling, it is always propagated outwards instead
70710 * of causing an infinite loop in our own handler.
70711 */
70712 heap->lj.jmpbuf_ptr = (duk_jmpbuf *) entry_jmpbuf_ptr;
70713
70714 lj_ret = duk__handle_longjmp(heap->curr_thread, entry_thread, entry_callstack_top);
70715
70716 if (lj_ret == DUK__LONGJMP_RESTART) {
70717 /* Restart bytecode execution, possibly with a changed thread. */
70718 ;
70719 } else {
70720 /* Rethrow error to calling state. */
70721 DUK_ASSERT(lj_ret == DUK__LONGJMP_RETHROW);
70722
70723 /* Longjmp handling has restored jmpbuf_ptr. */
70724 DUK_ASSERT(heap->lj.jmpbuf_ptr == entry_jmpbuf_ptr);
70725
70726 /* Thread may have changed, e.g. YIELD converted to THROW. */
70727 duk_err_longjmp(heap->curr_thread);
70728 DUK_UNREACHABLE();
70729 }
70730}
70731
70732/* Outer executor with setjmp/longjmp handling. */
70733DUK_INTERNAL void duk_js_execute_bytecode(duk_hthread *exec_thr) {
70734 /* Entry level info. */
70735 duk_hthread *entry_thread;
70736 duk_size_t entry_callstack_top;
70737 duk_int_t entry_call_recursion_depth;
70738 duk_jmpbuf *entry_jmpbuf_ptr;
70739 duk_jmpbuf our_jmpbuf;
70740 duk_heap *heap;
70741
70742 DUK_ASSERT(exec_thr != NULL);
70743 DUK_ASSERT(exec_thr->heap != NULL);
70744 DUK_ASSERT(exec_thr->heap->curr_thread != NULL);
70745 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR((duk_heaphdr *) exec_thr);
70746 DUK_ASSERT(exec_thr->callstack_top >= 1); /* at least one activation, ours */
70747 DUK_ASSERT(DUK_ACT_GET_FUNC(exec_thr->callstack + exec_thr->callstack_top - 1) != NULL);
70748 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(exec_thr->callstack + exec_thr->callstack_top - 1)));
70749
70750 entry_thread = exec_thr;
70751 heap = entry_thread->heap;
70752 entry_callstack_top = entry_thread->callstack_top;
70753 entry_call_recursion_depth = entry_thread->heap->call_recursion_depth;
70754 entry_jmpbuf_ptr = entry_thread->heap->lj.jmpbuf_ptr;
70755
70756 /*
70757 * Note: we currently assume that the setjmp() catchpoint is
70758 * not re-entrant (longjmp() cannot be called more than once
70759 * for a single setjmp()).
70760 *
70761 * See doc/code-issues.rst for notes on variable assignment
70762 * before and after setjmp().
70763 */
70764
70765 for (;;) {
70766 heap->lj.jmpbuf_ptr = &our_jmpbuf;
70767 DUK_ASSERT(heap->lj.jmpbuf_ptr != NULL);
70768
70769#if defined(DUK_USE_CPP_EXCEPTIONS)
70770 try {
70771#else
70772 DUK_ASSERT(heap->lj.jmpbuf_ptr == &our_jmpbuf);
70773 if (DUK_SETJMP(our_jmpbuf.jb) == 0) {
70774#endif
70775 /* Execute bytecode until returned or longjmp(). */
70776 duk__js_execute_bytecode_inner(entry_thread, entry_callstack_top);
70777
70778 /* Successful return: restore jmpbuf and return to caller. */
70779 heap->lj.jmpbuf_ptr = entry_jmpbuf_ptr;
70780
70781 return;
70782#if defined(DUK_USE_CPP_EXCEPTIONS)
70783 } catch (duk_internal_exception &exc) {
70784#else
70785 } else {
70786#endif
70787#if defined(DUK_USE_CPP_EXCEPTIONS)
70788 DUK_UNREF(exc);
70789#endif
70790 DUK_DDD(DUK_DDDPRINT("longjmp caught by bytecode executor"));
70791
70792 duk__handle_executor_error(heap,
70793 entry_thread,
70794 entry_callstack_top,
70795 entry_call_recursion_depth,
70796 entry_jmpbuf_ptr);
70797 }
70798#if defined(DUK_USE_CPP_EXCEPTIONS)
70799 catch (std::exception &exc) {
70800 const char *what = exc.what();
70801 if (!what) {
70802 what = "unknown";
70803 }
70804 DUK_D(DUK_DPRINT("unexpected c++ std::exception (perhaps thrown by user code)"));
70805 try {
70806 DUK_ASSERT(heap->curr_thread != NULL);
70807 DUK_ERROR_FMT1(heap->curr_thread, DUK_ERR_TYPE_ERROR, "caught invalid c++ std::exception '%s' (perhaps thrown by user code)", what);
70808 } catch (duk_internal_exception exc) {
70809 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ std::exception"));
70810 DUK_UNREF(exc);
70811 duk__handle_executor_error(heap,
70812 entry_thread,
70813 entry_callstack_top,
70814 entry_call_recursion_depth,
70815 entry_jmpbuf_ptr);
70816 }
70817 } catch (...) {
70818 DUK_D(DUK_DPRINT("unexpected c++ exception (perhaps thrown by user code)"));
70819 try {
70820 DUK_ASSERT(heap->curr_thread != NULL);
70821 DUK_ERROR_TYPE(heap->curr_thread, "caught invalid c++ exception (perhaps thrown by user code)");
70822 } catch (duk_internal_exception exc) {
70823 DUK_D(DUK_DPRINT("caught api error thrown from unexpected c++ exception"));
70824 DUK_UNREF(exc);
70825 duk__handle_executor_error(heap,
70826 entry_thread,
70827 entry_callstack_top,
70828 entry_call_recursion_depth,
70829 entry_jmpbuf_ptr);
70830 }
70831 }
70832#endif
70833 }
70834
70835 DUK_UNREACHABLE();
70836}
70837
70838/* Inner executor, performance critical. */
70839DUK_LOCAL DUK_NOINLINE void duk__js_execute_bytecode_inner(duk_hthread *entry_thread, duk_size_t entry_callstack_top) {
70840 /* Current PC, accessed by other functions through thr->ptr_to_curr_pc.
70841 * Critical for performance. It would be safest to make this volatile,
70842 * but that eliminates performance benefits; aliasing guarantees
70843 * should be enough though.
70844 */
70845 duk_instr_t *curr_pc; /* bytecode has a stable pointer */
70846
70847 /* Hot variables for interpretation. Critical for performance,
70848 * but must add sparingly to minimize register shuffling.
70849 */
70850 duk_hthread *thr; /* stable */
70851 duk_tval *consts; /* stable */
70852 duk_uint_fast32_t ins;
70853 /* 'funcs' is quite rarely used, so no local for it */
70854#if defined(DUK_USE_EXEC_FUN_LOCAL)
70855 duk_hcompfunc *fun;
70856#else
70857 /* 'fun' is quite rarely used, so no local for it */
70858#endif
70859
70860#if defined(DUK_USE_INTERRUPT_COUNTER)
70861 duk_int_t int_ctr;
70862#endif
70863
70864#if defined(DUK_USE_ASSERTIONS)
70865 duk_size_t valstack_top_base; /* valstack top, should match before interpreting each op (no leftovers) */
70866#endif
70867
70868 /* Optimized reg/const access macros assume sizeof(duk_tval) to be
70869 * either 8 or 16. Heap allocation checks this even without asserts
70870 * enabled now because it can't be autodetected in duk_config.h.
70871 */
70872#if 1
70873#if defined(DUK_USE_PACKED_TVAL)
70874 DUK_ASSERT(sizeof(duk_tval) == 8);
70875#else
70876 DUK_ASSERT(sizeof(duk_tval) == 16);
70877#endif
70878#endif
70879
70880 /*
70881 * Restart execution by reloading thread state.
70882 *
70883 * Note that 'thr' and any thread configuration may have changed,
70884 * so all local variables are suspect and we need to reinitialize.
70885 *
70886 * The number of local variables should be kept to a minimum: if
70887 * the variables are spilled, they will need to be loaded from
70888 * memory anyway.
70889 *
70890 * Any 'goto restart_execution;' code path in opcode dispatch must
70891 * ensure 'curr_pc' is synced back to act->curr_pc before the goto
70892 * takes place.
70893 *
70894 * The interpreter must be very careful with memory pointers, as
70895 * many pointers are not guaranteed to be 'stable' and may be
70896 * reallocated and relocated on-the-fly quite easily (e.g. by a
70897 * memory allocation or a property access).
70898 *
70899 * The following are assumed to have stable pointers:
70900 * - the current thread
70901 * - the current function
70902 * - the bytecode, constant table, inner function table of the
70903 * current function (as they are a part of the function allocation)
70904 *
70905 * The following are assumed to have semi-stable pointers:
70906 * - the current activation entry: stable as long as callstack
70907 * is not changed (reallocated by growing or shrinking), or
70908 * by any garbage collection invocation (through finalizers)
70909 * - Note in particular that ANY DECREF can invalidate the
70910 * activation pointer, so for the most part a fresh lookup
70911 * is required
70912 *
70913 * The following are not assumed to have stable pointers at all:
70914 * - the value stack (registers) of the current thread
70915 * - the catch stack of the current thread
70916 *
70917 * See execution.rst for discussion.
70918 */
70919
70920 restart_execution:
70921
70922 /* Lookup current thread; use the stable 'entry_thread' for this to
70923 * avoid clobber warnings. Any valid, reachable 'thr' value would be
70924 * fine for this, so using 'entry_thread' is just to silence warnings.
70925 */
70926 thr = entry_thread->heap->curr_thread;
70927 DUK_ASSERT(thr != NULL);
70928 DUK_ASSERT(thr->callstack_top >= 1);
70929 DUK_ASSERT(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1) != NULL);
70930 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_ACT_GET_FUNC(thr->callstack + thr->callstack_top - 1)));
70931
70932 thr->ptr_curr_pc = &curr_pc;
70933
70934 /* Relookup and initialize dispatch loop variables. Debugger check. */
70935 {
70936 duk_activation *act;
70937#if !defined(DUK_USE_EXEC_FUN_LOCAL)
70938 duk_hcompfunc *fun;
70939#endif
70940
70941 /* Assume interrupt init/counter are properly initialized here. */
70942 /* Assume that thr->valstack_bottom has been set-up before getting here. */
70943
70944 act = thr->callstack + thr->callstack_top - 1;
70945 fun = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
70946 DUK_ASSERT(fun != NULL);
70947 DUK_ASSERT(thr->valstack_top - thr->valstack_bottom == fun->nregs);
70948 consts = DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, fun);
70949 DUK_ASSERT(consts != NULL);
70950
70951#if defined(DUK_USE_DEBUGGER_SUPPORT)
70952 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap) && !thr->heap->dbg_processing) {
70953 duk__executor_recheck_debugger(thr, act, fun);
70954 act = thr->callstack + thr->callstack_top - 1; /* relookup after side effects (no side effects currently however) */
70955 }
70956#endif /* DUK_USE_DEBUGGER_SUPPORT */
70957
70958#if defined(DUK_USE_ASSERTIONS)
70959 valstack_top_base = (duk_size_t) (thr->valstack_top - thr->valstack);
70960#endif
70961
70962 /* Set up curr_pc for opcode dispatch. */
70963 curr_pc = act->curr_pc;
70964 }
70965
70966 DUK_DD(DUK_DDPRINT("restarting execution, thr %p, act idx %ld, fun %p,"
70967 "consts %p, funcs %p, lev %ld, regbot %ld, regtop %ld, catchstack_top=%ld, "
70968 "preventcount=%ld",
70969 (void *) thr,
70970 (long) (thr->callstack_top - 1),
70971 (void *) DUK__FUN(),
70972 (void *) DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, DUK__FUN()),
70973 (void *) DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, DUK__FUN()),
70974 (long) (thr->callstack_top - 1),
70975 (long) (thr->valstack_bottom - thr->valstack),
70976 (long) (thr->valstack_top - thr->valstack),
70977 (long) thr->catchstack_top,
70978 (long) thr->callstack_preventcount));
70979
70980 /* Dispatch loop. */
70981
70982 for (;;) {
70983 duk_uint8_t op;
70984
70985 DUK_ASSERT(thr->callstack_top >= 1);
70986 DUK_ASSERT(thr->valstack_top - thr->valstack_bottom == DUK__FUN()->nregs);
70987 DUK_ASSERT((duk_size_t) (thr->valstack_top - thr->valstack) == valstack_top_base);
70988
70989 /* Executor interrupt counter check, used to implement breakpoints,
70990 * debugging interface, execution timeouts, etc. The counter is heap
70991 * specific but is maintained in the current thread to make the check
70992 * as fast as possible. The counter is copied back to the heap struct
70993 * whenever a thread switch occurs by the DUK_HEAP_SWITCH_THREAD() macro.
70994 */
70995#if defined(DUK_USE_INTERRUPT_COUNTER)
70996 int_ctr = thr->interrupt_counter;
70997 if (DUK_LIKELY(int_ctr > 0)) {
70998 thr->interrupt_counter = int_ctr - 1;
70999 } else {
71000 /* Trigger at zero or below */
71001 duk_small_uint_t exec_int_ret;
71002
71003 /* Write curr_pc back for the debugger. */
71004 DUK_ASSERT(thr->callstack_top > 0);
71005 {
71006 duk_activation *act;
71007 act = thr->callstack + thr->callstack_top - 1;
71008 act->curr_pc = (duk_instr_t *) curr_pc;
71009 }
71010
71011 /* Force restart caused by a function return; must recheck
71012 * debugger breakpoints before checking line transitions,
71013 * see GH-303. Restart and then handle interrupt_counter
71014 * zero again.
71015 */
71016#if defined(DUK_USE_DEBUGGER_SUPPORT)
71017 if (thr->heap->dbg_force_restart) {
71018 DUK_DD(DUK_DDPRINT("dbg_force_restart flag forced restart execution")); /* GH-303 */
71019 thr->heap->dbg_force_restart = 0;
71020 goto restart_execution;
71021 }
71022#endif
71023
71024 exec_int_ret = duk__executor_interrupt(thr);
71025 if (exec_int_ret == DUK__INT_RESTART) {
71026 /* curr_pc synced back above */
71027 goto restart_execution;
71028 }
71029 }
71030#endif /* DUK_USE_INTERRUPT_COUNTER */
71031#if defined(DUK_USE_INTERRUPT_COUNTER) && defined(DUK_USE_DEBUG)
71032 /* For cross-checking during development: ensure dispatch count
71033 * matches cumulative interrupt counter init value sums.
71034 */
71035 thr->heap->inst_count_exec++;
71036#endif
71037
71038#if defined(DUK_USE_ASSERTIONS) || defined(DUK_USE_DEBUG)
71039 {
71040 duk_activation *act;
71041 act = thr->callstack + thr->callstack_top - 1;
71042 DUK_ASSERT(curr_pc >= DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, DUK__FUN()));
71043 DUK_ASSERT(curr_pc < DUK_HCOMPFUNC_GET_CODE_END(thr->heap, DUK__FUN()));
71044 DUK_UNREF(act); /* if debugging disabled */
71045
71046 DUK_DDD(DUK_DDDPRINT("executing bytecode: pc=%ld, ins=0x%08lx, op=%ld, valstack_top=%ld/%ld, nregs=%ld --> %!I",
71047 (long) (curr_pc - DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, DUK__FUN())),
71048 (unsigned long) *curr_pc,
71049 (long) DUK_DEC_OP(*curr_pc),
71050 (long) (thr->valstack_top - thr->valstack),
71051 (long) (thr->valstack_end - thr->valstack),
71052 (long) (DUK__FUN() ? DUK__FUN()->nregs : -1),
71053 (duk_instr_t) *curr_pc));
71054 }
71055#endif
71056
71057#if defined(DUK_USE_ASSERTIONS)
71058 /* Quite heavy assert: check valstack policy. Improper
71059 * shuffle instructions can write beyond valstack_top/end
71060 * so this check catches them in the act.
71061 */
71062 {
71063 duk_tval *tv;
71064 tv = thr->valstack_top;
71065 while (tv != thr->valstack_end) {
71066 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(tv));
71067 tv++;
71068 }
71069 }
71070#endif
71071
71072 ins = *curr_pc++;
71073
71074 /* Typing: use duk_small_(u)int_fast_t when decoding small
71075 * opcode fields (op, A, B, C, BC) which fit into 16 bits
71076 * and duk_(u)int_fast_t when decoding larger fields (e.g.
71077 * ABC). Use unsigned variant by default, signed when the
71078 * value is used in signed arithmetic. Using variable names
71079 * such as 'a', 'b', 'c', 'bc', etc makes it easier to spot
71080 * typing mismatches.
71081 */
71082
71083 /* Switch based on opcode. Cast to 8-bit unsigned value and
71084 * use a fully populated case clauses so that the compiler
71085 * will (at least usually) omit a bounds check.
71086 */
71087 op = (duk_uint8_t) DUK_DEC_OP(ins);
71088 switch (op) {
71089
71090 /* Some useful macros. These access inner executor variables
71091 * directly so they only apply within the executor.
71092 */
71093#if defined(DUK_USE_EXEC_PREFER_SIZE)
71094#define DUK__REPLACE_TOP_A_BREAK() { goto replace_top_a; }
71095#define DUK__REPLACE_TOP_BC_BREAK() { goto replace_top_bc; }
71096#define DUK__REPLACE_BOOL_A_BREAK(bval) { \
71097 duk_bool_t duk__bval; \
71098 duk__bval = (bval); \
71099 DUK_ASSERT(duk__bval == 0 || duk__bval == 1); \
71100 duk_push_boolean((duk_context *) thr, duk__bval); \
71101 DUK__REPLACE_TOP_A_BREAK(); \
71102 }
71103#else
71104#define DUK__REPLACE_TOP_A_BREAK() { DUK__REPLACE_TO_TVPTR(thr, DUK__REGP_A(ins)); break; }
71105#define DUK__REPLACE_TOP_BC_BREAK() { DUK__REPLACE_TO_TVPTR(thr, DUK__REGP_BC(ins)); break; }
71106#define DUK__REPLACE_BOOL_A_BREAK(bval) { \
71107 duk_bool_t duk__bval; \
71108 duk_tval *duk__tvdst; \
71109 duk__bval = (bval); \
71110 DUK_ASSERT(duk__bval == 0 || duk__bval == 1); \
71111 duk__tvdst = DUK__REGP_A(ins); \
71112 DUK_TVAL_SET_BOOLEAN_UPDREF(thr, duk__tvdst, duk__bval); \
71113 break; \
71114 }
71115#endif
71116
71117 /* XXX: 12 + 12 bit variant might make sense too, for both reg and
71118 * const loads.
71119 */
71120
71121 /* For LDREG, STREG, LDCONST footprint optimized variants would just
71122 * duk_dup() + duk_replace(), but because they're used quite a lot
71123 * they're currently intentionally not size optimized.
71124 */
71125 case DUK_OP_LDREG: {
71126 duk_tval *tv1, *tv2;
71127
71128 tv1 = DUK__REGP_A(ins);
71129 tv2 = DUK__REGP_BC(ins);
71130 DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2); /* side effects */
71131 break;
71132 }
71133
71134 case DUK_OP_STREG: {
71135 duk_tval *tv1, *tv2;
71136
71137 tv1 = DUK__REGP_A(ins);
71138 tv2 = DUK__REGP_BC(ins);
71139 DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv2, tv1); /* side effects */
71140 break;
71141 }
71142
71143 case DUK_OP_LDCONST: {
71144 duk_tval *tv1, *tv2;
71145
71146 tv1 = DUK__REGP_A(ins);
71147 tv2 = DUK__CONSTP_BC(ins);
71148 DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2); /* side effects */
71149 break;
71150 }
71151
71152 /* LDINT and LDINTX are intended to load an arbitrary signed
71153 * 32-bit value. Only an LDINT+LDINTX sequence is supported.
71154 * This also guarantees all values remain fastints.
71155 */
71156#if defined(DUK_USE_EXEC_PREFER_SIZE)
71157 case DUK_OP_LDINT: {
71158 duk_int32_t val;
71159
71160 val = (duk_int32_t) DUK_DEC_BC(ins) - (duk_int32_t) DUK_BC_LDINT_BIAS;
71161 duk_push_int((duk_context *) thr, val);
71162 DUK__REPLACE_TOP_A_BREAK();
71163 }
71164 case DUK_OP_LDINTX: {
71165 duk_int32_t val;
71166
71167 val = (duk_int32_t) duk_get_int((duk_context *) thr, DUK_DEC_A(ins));
71168 val = (val << DUK_BC_LDINTX_SHIFT) + (duk_int32_t) DUK_DEC_BC(ins); /* no bias */
71169 duk_push_int((duk_context *) thr, val);
71170 DUK__REPLACE_TOP_A_BREAK();
71171 }
71172#else /* DUK_USE_EXEC_PREFER_SIZE */
71173 case DUK_OP_LDINT: {
71174 duk_tval *tv1;
71175 duk_int32_t val;
71176
71177 val = (duk_int32_t) DUK_DEC_BC(ins) - (duk_int32_t) DUK_BC_LDINT_BIAS;
71178 tv1 = DUK__REGP_A(ins);
71179 DUK_TVAL_SET_I32_UPDREF(thr, tv1, val); /* side effects */
71180 break;
71181 }
71182 case DUK_OP_LDINTX: {
71183 duk_tval *tv1;
71184 duk_int32_t val;
71185
71186 tv1 = DUK__REGP_A(ins);
71187 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
71188#if defined(DUK_USE_FASTINT)
71189 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1));
71190 val = DUK_TVAL_GET_FASTINT_I32(tv1);
71191#else
71192 /* XXX: fast double-to-int conversion, we know number is integer in [-0x80000000,0xffffffff]. */
71193 val = (duk_int32_t) DUK_TVAL_GET_NUMBER(tv1);
71194#endif
71195 val = (val << DUK_BC_LDINTX_SHIFT) + (duk_int32_t) DUK_DEC_BC(ins); /* no bias */
71196 DUK_TVAL_SET_I32_UPDREF(thr, tv1, val); /* side effects */
71197 break;
71198 }
71199#endif /* DUK_USE_EXEC_PREFER_SIZE */
71200
71201#if defined(DUK_USE_EXEC_PREFER_SIZE)
71202 case DUK_OP_LDTHIS: {
71203 duk_push_this((duk_context *) thr);
71204 DUK__REPLACE_TOP_BC_BREAK();
71205 }
71206 case DUK_OP_LDUNDEF: {
71207 duk_to_undefined((duk_context *) thr, (duk_idx_t) DUK_DEC_BC(ins));
71208 break;
71209 }
71210 case DUK_OP_LDNULL: {
71211 duk_to_null((duk_context *) thr, (duk_idx_t) DUK_DEC_BC(ins));
71212 break;
71213 }
71214 case DUK_OP_LDTRUE: {
71215 duk_push_true((duk_context *) thr);
71216 DUK__REPLACE_TOP_BC_BREAK();
71217 }
71218 case DUK_OP_LDFALSE: {
71219 duk_push_false((duk_context *) thr);
71220 DUK__REPLACE_TOP_BC_BREAK();
71221 }
71222#else /* DUK_USE_EXEC_PREFER_SIZE */
71223 case DUK_OP_LDTHIS: {
71224 /* Note: 'this' may be bound to any value, not just an object */
71225 duk_tval *tv1, *tv2;
71226
71227 tv1 = DUK__REGP_BC(ins);
71228 tv2 = thr->valstack_bottom - 1; /* 'this binding' is just under bottom */
71229 DUK_ASSERT(tv2 >= thr->valstack);
71230 DUK_TVAL_SET_TVAL_UPDREF_FAST(thr, tv1, tv2); /* side effects */
71231 break;
71232 }
71233 case DUK_OP_LDUNDEF: {
71234 duk_tval *tv1;
71235
71236 tv1 = DUK__REGP_BC(ins);
71237 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */
71238 break;
71239 }
71240 case DUK_OP_LDNULL: {
71241 duk_tval *tv1;
71242
71243 tv1 = DUK__REGP_BC(ins);
71244 DUK_TVAL_SET_NULL_UPDREF(thr, tv1); /* side effects */
71245 break;
71246 }
71247 case DUK_OP_LDTRUE: {
71248 duk_tval *tv1;
71249
71250 tv1 = DUK__REGP_BC(ins);
71251 DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv1, 1); /* side effects */
71252 break;
71253 }
71254 case DUK_OP_LDFALSE: {
71255 duk_tval *tv1;
71256
71257 tv1 = DUK__REGP_BC(ins);
71258 DUK_TVAL_SET_BOOLEAN_UPDREF(thr, tv1, 0); /* side effects */
71259 break;
71260 }
71261#endif /* DUK_USE_EXEC_PREFER_SIZE */
71262
71263 case DUK_OP_BNOT: {
71264 duk__vm_bitwise_not(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins));
71265 break;
71266 }
71267
71268 case DUK_OP_LNOT: {
71269 duk__vm_logical_not(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins));
71270 break;
71271 }
71272
71273#if defined(DUK_USE_EXEC_PREFER_SIZE)
71274 case DUK_OP_UNM:
71275 case DUK_OP_UNP: {
71276 duk__vm_arith_unary_op(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins), op);
71277 break;
71278 }
71279#else /* DUK_USE_EXEC_PREFER_SIZE */
71280 case DUK_OP_UNM: {
71281 duk__vm_arith_unary_op(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins), DUK_OP_UNM);
71282 break;
71283 }
71284 case DUK_OP_UNP: {
71285 duk__vm_arith_unary_op(thr, DUK_DEC_BC(ins), DUK_DEC_A(ins), DUK_OP_UNP);
71286 break;
71287 }
71288#endif /* DUK_USE_EXEC_PREFER_SIZE */
71289
71290#if defined(DUK_USE_EXEC_PREFER_SIZE)
71291 case DUK_OP_TYPEOF: {
71292 duk_small_uint_t stridx;
71293
71294 stridx = duk_js_typeof_stridx(DUK__REGP_BC(ins));
71295 DUK_ASSERT(stridx >= 0 && stridx < DUK_HEAP_NUM_STRINGS);
71296 duk_push_hstring_stridx((duk_context *) thr, stridx);
71297 DUK__REPLACE_TOP_A_BREAK();
71298 }
71299#else /* DUK_USE_EXEC_PREFER_SIZE */
71300 case DUK_OP_TYPEOF: {
71301 duk_tval *tv;
71302 duk_small_uint_t stridx;
71303 duk_hstring *h_str;
71304
71305 tv = DUK__REGP_BC(ins);
71306 stridx = duk_js_typeof_stridx(tv);
71307 DUK_ASSERT_STRIDX_VALID(stridx);
71308 h_str = DUK_HTHREAD_GET_STRING(thr, stridx);
71309 tv = DUK__REGP_A(ins);
71310 DUK_TVAL_SET_STRING_UPDREF(thr, tv, h_str);
71311 break;
71312 }
71313#endif /* DUK_USE_EXEC_PREFER_SIZE */
71314
71315 case DUK_OP_TYPEOFID: {
71316 duk_context *ctx = (duk_context *) thr;
71317 duk_small_uint_t stridx;
71318#if !defined(DUK_USE_EXEC_PREFER_SIZE)
71319 duk_hstring *h_str;
71320#endif
71321 duk_activation *act;
71322 duk_hstring *name;
71323 duk_tval *tv;
71324
71325 /* A -> target register
71326 * BC -> constant index of identifier name
71327 */
71328
71329 tv = DUK__CONSTP_BC(ins);
71330 DUK_ASSERT(DUK_TVAL_IS_STRING(tv));
71331 name = DUK_TVAL_GET_STRING(tv);
71332 tv = NULL; /* lookup has side effects */
71333 act = thr->callstack + thr->callstack_top - 1;
71334 if (duk_js_getvar_activation(thr, act, name, 0 /*throw*/)) {
71335 /* -> [... val this] */
71336 tv = DUK_GET_TVAL_NEGIDX(ctx, -2);
71337 stridx = duk_js_typeof_stridx(tv);
71338 tv = NULL; /* no longer needed */
71339 duk_pop_2(ctx);
71340 } else {
71341 /* unresolvable, no stack changes */
71342 stridx = DUK_STRIDX_LC_UNDEFINED;
71343 }
71344 DUK_ASSERT_STRIDX_VALID(stridx);
71345#if defined(DUK_USE_EXEC_PREFER_SIZE)
71346 duk_push_hstring_stridx(ctx, stridx);
71347 DUK__REPLACE_TOP_A_BREAK();
71348#else /* DUK_USE_EXEC_PREFER_SIZE */
71349 h_str = DUK_HTHREAD_GET_STRING(thr, stridx);
71350 tv = DUK__REGP_A(ins);
71351 DUK_TVAL_SET_STRING_UPDREF(thr, tv, h_str);
71352 break;
71353#endif /* DUK_USE_EXEC_PREFER_SIZE */
71354 }
71355
71356 /* Equality: E5 Sections 11.9.1, 11.9.3 */
71357
71358#define DUK__EQ_BODY(barg,carg) { \
71359 duk_bool_t tmp; \
71360 tmp = duk_js_equals(thr, (barg), (carg)); \
71361 DUK_ASSERT(tmp == 0 || tmp == 1); \
71362 DUK__REPLACE_BOOL_A_BREAK(tmp); \
71363 }
71364#define DUK__NEQ_BODY(barg,carg) { \
71365 duk_bool_t tmp; \
71366 tmp = duk_js_equals(thr, (barg), (carg)); \
71367 DUK_ASSERT(tmp == 0 || tmp == 1); \
71368 tmp ^= 1; \
71369 DUK__REPLACE_BOOL_A_BREAK(tmp); \
71370 }
71371#define DUK__SEQ_BODY(barg,carg) { \
71372 duk_bool_t tmp; \
71373 tmp = duk_js_strict_equals((barg), (carg)); \
71374 DUK_ASSERT(tmp == 0 || tmp == 1); \
71375 DUK__REPLACE_BOOL_A_BREAK(tmp); \
71376 }
71377#define DUK__SNEQ_BODY(barg,carg) { \
71378 duk_bool_t tmp; \
71379 tmp = duk_js_strict_equals((barg), (carg)); \
71380 DUK_ASSERT(tmp == 0 || tmp == 1); \
71381 tmp ^= 1; \
71382 DUK__REPLACE_BOOL_A_BREAK(tmp); \
71383 }
71384#if defined(DUK_USE_EXEC_PREFER_SIZE)
71385 case DUK_OP_EQ_RR:
71386 case DUK_OP_EQ_CR:
71387 case DUK_OP_EQ_RC:
71388 case DUK_OP_EQ_CC:
71389 DUK__EQ_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
71390 case DUK_OP_NEQ_RR:
71391 case DUK_OP_NEQ_CR:
71392 case DUK_OP_NEQ_RC:
71393 case DUK_OP_NEQ_CC:
71394 DUK__NEQ_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
71395 case DUK_OP_SEQ_RR:
71396 case DUK_OP_SEQ_CR:
71397 case DUK_OP_SEQ_RC:
71398 case DUK_OP_SEQ_CC:
71399 DUK__SEQ_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
71400 case DUK_OP_SNEQ_RR:
71401 case DUK_OP_SNEQ_CR:
71402 case DUK_OP_SNEQ_RC:
71403 case DUK_OP_SNEQ_CC:
71404 DUK__SNEQ_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
71405#else /* DUK_USE_EXEC_PREFER_SIZE */
71406 case DUK_OP_EQ_RR:
71407 DUK__EQ_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
71408 case DUK_OP_EQ_CR:
71409 DUK__EQ_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
71410 case DUK_OP_EQ_RC:
71411 DUK__EQ_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
71412 case DUK_OP_EQ_CC:
71413 DUK__EQ_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
71414 case DUK_OP_NEQ_RR:
71415 DUK__NEQ_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
71416 case DUK_OP_NEQ_CR:
71417 DUK__NEQ_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
71418 case DUK_OP_NEQ_RC:
71419 DUK__NEQ_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
71420 case DUK_OP_NEQ_CC:
71421 DUK__NEQ_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
71422 case DUK_OP_SEQ_RR:
71423 DUK__SEQ_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
71424 case DUK_OP_SEQ_CR:
71425 DUK__SEQ_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
71426 case DUK_OP_SEQ_RC:
71427 DUK__SEQ_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
71428 case DUK_OP_SEQ_CC:
71429 DUK__SEQ_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
71430 case DUK_OP_SNEQ_RR:
71431 DUK__SNEQ_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
71432 case DUK_OP_SNEQ_CR:
71433 DUK__SNEQ_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
71434 case DUK_OP_SNEQ_RC:
71435 DUK__SNEQ_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
71436 case DUK_OP_SNEQ_CC:
71437 DUK__SNEQ_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
71438#endif /* DUK_USE_EXEC_PREFER_SIZE */
71439
71440#define DUK__COMPARE_BODY(arg1,arg2,flags) { \
71441 duk_bool_t tmp; \
71442 tmp = duk_js_compare_helper(thr, (arg1), (arg2), (flags)); \
71443 DUK_ASSERT(tmp == 0 || tmp == 1); \
71444 DUK__REPLACE_BOOL_A_BREAK(tmp); \
71445 }
71446#define DUK__GT_BODY(barg,carg) DUK__COMPARE_BODY((carg), (barg), 0)
71447#define DUK__GE_BODY(barg,carg) DUK__COMPARE_BODY((barg), (carg), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST | DUK_COMPARE_FLAG_NEGATE)
71448#define DUK__LT_BODY(barg,carg) DUK__COMPARE_BODY((barg), (carg), DUK_COMPARE_FLAG_EVAL_LEFT_FIRST)
71449#define DUK__LE_BODY(barg,carg) DUK__COMPARE_BODY((carg), (barg), DUK_COMPARE_FLAG_NEGATE)
71450#if defined(DUK_USE_EXEC_PREFER_SIZE)
71451 case DUK_OP_GT_RR:
71452 case DUK_OP_GT_CR:
71453 case DUK_OP_GT_RC:
71454 case DUK_OP_GT_CC:
71455 DUK__GT_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
71456 case DUK_OP_GE_RR:
71457 case DUK_OP_GE_CR:
71458 case DUK_OP_GE_RC:
71459 case DUK_OP_GE_CC:
71460 DUK__GE_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
71461 case DUK_OP_LT_RR:
71462 case DUK_OP_LT_CR:
71463 case DUK_OP_LT_RC:
71464 case DUK_OP_LT_CC:
71465 DUK__LT_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
71466 case DUK_OP_LE_RR:
71467 case DUK_OP_LE_CR:
71468 case DUK_OP_LE_RC:
71469 case DUK_OP_LE_CC:
71470 DUK__LE_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
71471#else /* DUK_USE_EXEC_PREFER_SIZE */
71472 case DUK_OP_GT_RR:
71473 DUK__GT_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
71474 case DUK_OP_GT_CR:
71475 DUK__GT_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
71476 case DUK_OP_GT_RC:
71477 DUK__GT_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
71478 case DUK_OP_GT_CC:
71479 DUK__GT_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
71480 case DUK_OP_GE_RR:
71481 DUK__GE_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
71482 case DUK_OP_GE_CR:
71483 DUK__GE_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
71484 case DUK_OP_GE_RC:
71485 DUK__GE_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
71486 case DUK_OP_GE_CC:
71487 DUK__GE_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
71488 case DUK_OP_LT_RR:
71489 DUK__LT_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
71490 case DUK_OP_LT_CR:
71491 DUK__LT_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
71492 case DUK_OP_LT_RC:
71493 DUK__LT_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
71494 case DUK_OP_LT_CC:
71495 DUK__LT_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
71496 case DUK_OP_LE_RR:
71497 DUK__LE_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
71498 case DUK_OP_LE_CR:
71499 DUK__LE_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
71500 case DUK_OP_LE_RC:
71501 DUK__LE_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
71502 case DUK_OP_LE_CC:
71503 DUK__LE_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
71504#endif /* DUK_USE_EXEC_PREFER_SIZE */
71505
71506 /* No size optimized variant at present for IF. */
71507 case DUK_OP_IFTRUE_R: {
71508 if (duk_js_toboolean(DUK__REGP_BC(ins)) != 0) {
71509 curr_pc++;
71510 }
71511 break;
71512 }
71513 case DUK_OP_IFTRUE_C: {
71514 if (duk_js_toboolean(DUK__CONSTP_BC(ins)) != 0) {
71515 curr_pc++;
71516 }
71517 break;
71518 }
71519 case DUK_OP_IFFALSE_R: {
71520 if (duk_js_toboolean(DUK__REGP_BC(ins)) == 0) {
71521 curr_pc++;
71522 }
71523 break;
71524 }
71525 case DUK_OP_IFFALSE_C: {
71526 if (duk_js_toboolean(DUK__CONSTP_BC(ins)) == 0) {
71527 curr_pc++;
71528 }
71529 break;
71530 }
71531
71532#if defined(DUK_USE_EXEC_PREFER_SIZE)
71533 case DUK_OP_ADD_RR:
71534 case DUK_OP_ADD_CR:
71535 case DUK_OP_ADD_RC:
71536 case DUK_OP_ADD_CC: {
71537 /* XXX: could leave value on stack top and goto replace_top_a; */
71538 duk__vm_arith_add(thr, DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins), DUK_DEC_A(ins));
71539 break;
71540 }
71541#else /* DUK_USE_EXEC_PREFER_SIZE */
71542 case DUK_OP_ADD_RR: {
71543 duk__vm_arith_add(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins));
71544 break;
71545 }
71546 case DUK_OP_ADD_CR: {
71547 duk__vm_arith_add(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins));
71548 break;
71549 }
71550 case DUK_OP_ADD_RC: {
71551 duk__vm_arith_add(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins));
71552 break;
71553 }
71554 case DUK_OP_ADD_CC: {
71555 duk__vm_arith_add(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins));
71556 break;
71557 }
71558#endif /* DUK_USE_EXEC_PREFER_SIZE */
71559
71560#if defined(DUK_USE_EXEC_PREFER_SIZE)
71561 case DUK_OP_SUB_RR:
71562 case DUK_OP_SUB_CR:
71563 case DUK_OP_SUB_RC:
71564 case DUK_OP_SUB_CC:
71565 case DUK_OP_MUL_RR:
71566 case DUK_OP_MUL_CR:
71567 case DUK_OP_MUL_RC:
71568 case DUK_OP_MUL_CC:
71569 case DUK_OP_DIV_RR:
71570 case DUK_OP_DIV_CR:
71571 case DUK_OP_DIV_RC:
71572 case DUK_OP_DIV_CC:
71573 case DUK_OP_MOD_RR:
71574 case DUK_OP_MOD_CR:
71575 case DUK_OP_MOD_RC:
71576 case DUK_OP_MOD_CC:
71577#if defined(DUK_USE_ES7_EXP_OPERATOR)
71578 case DUK_OP_EXP_RR:
71579 case DUK_OP_EXP_CR:
71580 case DUK_OP_EXP_RC:
71581 case DUK_OP_EXP_CC:
71582#endif /* DUK_USE_ES7_EXP_OPERATOR */
71583 {
71584 /* XXX: could leave value on stack top and goto replace_top_a; */
71585 duk__vm_arith_binary_op(thr, DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins), DUK_DEC_A(ins), op);
71586 break;
71587 }
71588#else /* DUK_USE_EXEC_PREFER_SIZE */
71589 case DUK_OP_SUB_RR: {
71590 duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_SUB);
71591 break;
71592 }
71593 case DUK_OP_SUB_CR: {
71594 duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_SUB);
71595 break;
71596 }
71597 case DUK_OP_SUB_RC: {
71598 duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_SUB);
71599 break;
71600 }
71601 case DUK_OP_SUB_CC: {
71602 duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_SUB);
71603 break;
71604 }
71605 case DUK_OP_MUL_RR: {
71606 duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_MUL);
71607 break;
71608 }
71609 case DUK_OP_MUL_CR: {
71610 duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_MUL);
71611 break;
71612 }
71613 case DUK_OP_MUL_RC: {
71614 duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_MUL);
71615 break;
71616 }
71617 case DUK_OP_MUL_CC: {
71618 duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_MUL);
71619 break;
71620 }
71621 case DUK_OP_DIV_RR: {
71622 duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_DIV);
71623 break;
71624 }
71625 case DUK_OP_DIV_CR: {
71626 duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_DIV);
71627 break;
71628 }
71629 case DUK_OP_DIV_RC: {
71630 duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_DIV);
71631 break;
71632 }
71633 case DUK_OP_DIV_CC: {
71634 duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_DIV);
71635 break;
71636 }
71637 case DUK_OP_MOD_RR: {
71638 duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_MOD);
71639 break;
71640 }
71641 case DUK_OP_MOD_CR: {
71642 duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_MOD);
71643 break;
71644 }
71645 case DUK_OP_MOD_RC: {
71646 duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_MOD);
71647 break;
71648 }
71649 case DUK_OP_MOD_CC: {
71650 duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_MOD);
71651 break;
71652 }
71653#if defined(DUK_USE_ES7_EXP_OPERATOR)
71654 case DUK_OP_EXP_RR: {
71655 duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_EXP);
71656 break;
71657 }
71658 case DUK_OP_EXP_CR: {
71659 duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_EXP);
71660 break;
71661 }
71662 case DUK_OP_EXP_RC: {
71663 duk__vm_arith_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_EXP);
71664 break;
71665 }
71666 case DUK_OP_EXP_CC: {
71667 duk__vm_arith_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_EXP);
71668 break;
71669 }
71670#endif /* DUK_USE_ES7_EXP_OPERATOR */
71671#endif /* DUK_USE_EXEC_PREFER_SIZE */
71672
71673#if defined(DUK_USE_EXEC_PREFER_SIZE)
71674 case DUK_OP_BAND_RR:
71675 case DUK_OP_BAND_CR:
71676 case DUK_OP_BAND_RC:
71677 case DUK_OP_BAND_CC:
71678 case DUK_OP_BOR_RR:
71679 case DUK_OP_BOR_CR:
71680 case DUK_OP_BOR_RC:
71681 case DUK_OP_BOR_CC:
71682 case DUK_OP_BXOR_RR:
71683 case DUK_OP_BXOR_CR:
71684 case DUK_OP_BXOR_RC:
71685 case DUK_OP_BXOR_CC:
71686 case DUK_OP_BASL_RR:
71687 case DUK_OP_BASL_CR:
71688 case DUK_OP_BASL_RC:
71689 case DUK_OP_BASL_CC:
71690 case DUK_OP_BLSR_RR:
71691 case DUK_OP_BLSR_CR:
71692 case DUK_OP_BLSR_RC:
71693 case DUK_OP_BLSR_CC:
71694 case DUK_OP_BASR_RR:
71695 case DUK_OP_BASR_CR:
71696 case DUK_OP_BASR_RC:
71697 case DUK_OP_BASR_CC: {
71698 /* XXX: could leave value on stack top and goto replace_top_a; */
71699 duk__vm_bitwise_binary_op(thr, DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins), DUK_DEC_A(ins), op);
71700 break;
71701 }
71702#else /* DUK_USE_EXEC_PREFER_SIZE */
71703 case DUK_OP_BAND_RR: {
71704 duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BAND);
71705 break;
71706 }
71707 case DUK_OP_BAND_CR: {
71708 duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BAND);
71709 break;
71710 }
71711 case DUK_OP_BAND_RC: {
71712 duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BAND);
71713 break;
71714 }
71715 case DUK_OP_BAND_CC: {
71716 duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BAND);
71717 break;
71718 }
71719 case DUK_OP_BOR_RR: {
71720 duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BOR);
71721 break;
71722 }
71723 case DUK_OP_BOR_CR: {
71724 duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BOR);
71725 break;
71726 }
71727 case DUK_OP_BOR_RC: {
71728 duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BOR);
71729 break;
71730 }
71731 case DUK_OP_BOR_CC: {
71732 duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BOR);
71733 break;
71734 }
71735 case DUK_OP_BXOR_RR: {
71736 duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BXOR);
71737 break;
71738 }
71739 case DUK_OP_BXOR_CR: {
71740 duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BXOR);
71741 break;
71742 }
71743 case DUK_OP_BXOR_RC: {
71744 duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BXOR);
71745 break;
71746 }
71747 case DUK_OP_BXOR_CC: {
71748 duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BXOR);
71749 break;
71750 }
71751 case DUK_OP_BASL_RR: {
71752 duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BASL);
71753 break;
71754 }
71755 case DUK_OP_BASL_CR: {
71756 duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BASL);
71757 break;
71758 }
71759 case DUK_OP_BASL_RC: {
71760 duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BASL);
71761 break;
71762 }
71763 case DUK_OP_BASL_CC: {
71764 duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BASL);
71765 break;
71766 }
71767 case DUK_OP_BLSR_RR: {
71768 duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BLSR);
71769 break;
71770 }
71771 case DUK_OP_BLSR_CR: {
71772 duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BLSR);
71773 break;
71774 }
71775 case DUK_OP_BLSR_RC: {
71776 duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BLSR);
71777 break;
71778 }
71779 case DUK_OP_BLSR_CC: {
71780 duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BLSR);
71781 break;
71782 }
71783 case DUK_OP_BASR_RR: {
71784 duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BASR);
71785 break;
71786 }
71787 case DUK_OP_BASR_CR: {
71788 duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__REGP_C(ins), DUK_DEC_A(ins), DUK_OP_BASR);
71789 break;
71790 }
71791 case DUK_OP_BASR_RC: {
71792 duk__vm_bitwise_binary_op(thr, DUK__REGP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BASR);
71793 break;
71794 }
71795 case DUK_OP_BASR_CC: {
71796 duk__vm_bitwise_binary_op(thr, DUK__CONSTP_B(ins), DUK__CONSTP_C(ins), DUK_DEC_A(ins), DUK_OP_BASR);
71797 break;
71798 }
71799#endif /* DUK_USE_EXEC_PREFER_SIZE */
71800
71801 /* For INSTOF and IN, B is always a register. */
71802#define DUK__INSTOF_BODY(barg,carg) { \
71803 duk_bool_t tmp; \
71804 tmp = duk_js_instanceof(thr, (barg), (carg)); \
71805 DUK_ASSERT(tmp == 0 || tmp == 1); \
71806 DUK__REPLACE_BOOL_A_BREAK(tmp); \
71807 }
71808#define DUK__IN_BODY(barg,carg) { \
71809 duk_bool_t tmp; \
71810 tmp = duk_js_in(thr, (barg), (carg)); \
71811 DUK_ASSERT(tmp == 0 || tmp == 1); \
71812 DUK__REPLACE_BOOL_A_BREAK(tmp); \
71813 }
71814#if defined(DUK_USE_EXEC_PREFER_SIZE)
71815 case DUK_OP_INSTOF_RR:
71816 case DUK_OP_INSTOF_CR:
71817 case DUK_OP_INSTOF_RC:
71818 case DUK_OP_INSTOF_CC:
71819 DUK__INSTOF_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
71820 case DUK_OP_IN_RR:
71821 case DUK_OP_IN_CR:
71822 case DUK_OP_IN_RC:
71823 case DUK_OP_IN_CC:
71824 DUK__IN_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
71825#else /* DUK_USE_EXEC_PREFER_SIZE */
71826 case DUK_OP_INSTOF_RR:
71827 DUK__INSTOF_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
71828 case DUK_OP_INSTOF_CR:
71829 DUK__INSTOF_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
71830 case DUK_OP_INSTOF_RC:
71831 DUK__INSTOF_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
71832 case DUK_OP_INSTOF_CC:
71833 DUK__INSTOF_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
71834 case DUK_OP_IN_RR:
71835 DUK__IN_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
71836 case DUK_OP_IN_CR:
71837 DUK__IN_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
71838 case DUK_OP_IN_RC:
71839 DUK__IN_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
71840 case DUK_OP_IN_CC:
71841 DUK__IN_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
71842#endif /* DUK_USE_EXEC_PREFER_SIZE */
71843
71844 /* Pre/post inc/dec for register variables, important for loops. */
71845#if defined(DUK_USE_EXEC_PREFER_SIZE)
71846 case DUK_OP_PREINCR:
71847 case DUK_OP_PREDECR:
71848 case DUK_OP_POSTINCR:
71849 case DUK_OP_POSTDECR: {
71850 duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), op);
71851 break;
71852 }
71853 case DUK_OP_PREINCV:
71854 case DUK_OP_PREDECV:
71855 case DUK_OP_POSTINCV:
71856 case DUK_OP_POSTDECV: {
71857 duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), op, DUK__STRICT());
71858 break;
71859 }
71860#else /* DUK_USE_EXEC_PREFER_SIZE */
71861 case DUK_OP_PREINCR: {
71862 duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), DUK_OP_PREINCR);
71863 break;
71864 }
71865 case DUK_OP_PREDECR: {
71866 duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), DUK_OP_PREDECR);
71867 break;
71868 }
71869 case DUK_OP_POSTINCR: {
71870 duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), DUK_OP_POSTINCR);
71871 break;
71872 }
71873 case DUK_OP_POSTDECR: {
71874 duk__prepost_incdec_reg_helper(thr, DUK__REGP_A(ins), DUK__REGP_BC(ins), DUK_OP_POSTDECR);
71875 break;
71876 }
71877 case DUK_OP_PREINCV: {
71878 duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), DUK_OP_PREINCV, DUK__STRICT());
71879 break;
71880 }
71881 case DUK_OP_PREDECV: {
71882 duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), DUK_OP_PREDECV, DUK__STRICT());
71883 break;
71884 }
71885 case DUK_OP_POSTINCV: {
71886 duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), DUK_OP_POSTINCV, DUK__STRICT());
71887 break;
71888 }
71889 case DUK_OP_POSTDECV: {
71890 duk__prepost_incdec_var_helper(thr, DUK_DEC_A(ins), DUK__CONSTP_BC(ins), DUK_OP_POSTDECV, DUK__STRICT());
71891 break;
71892 }
71893#endif /* DUK_USE_EXEC_PREFER_SIZE */
71894
71895 /* XXX: Move to separate helper, optimize for perf/size separately. */
71896 /* Preinc/predec for object properties. */
71897 case DUK_OP_PREINCP_RR:
71898 case DUK_OP_PREINCP_CR:
71899 case DUK_OP_PREINCP_RC:
71900 case DUK_OP_PREINCP_CC:
71901 case DUK_OP_PREDECP_RR:
71902 case DUK_OP_PREDECP_CR:
71903 case DUK_OP_PREDECP_RC:
71904 case DUK_OP_PREDECP_CC:
71905 case DUK_OP_POSTINCP_RR:
71906 case DUK_OP_POSTINCP_CR:
71907 case DUK_OP_POSTINCP_RC:
71908 case DUK_OP_POSTINCP_CC:
71909 case DUK_OP_POSTDECP_RR:
71910 case DUK_OP_POSTDECP_CR:
71911 case DUK_OP_POSTDECP_RC:
71912 case DUK_OP_POSTDECP_CC: {
71913 duk_context *ctx = (duk_context *) thr;
71914 duk_tval *tv_obj;
71915 duk_tval *tv_key;
71916 duk_tval *tv_val;
71917 duk_bool_t rc;
71918 duk_double_t x, y, z;
71919#if !defined(DUK_USE_EXEC_PREFER_SIZE)
71920 duk_tval *tv_dst;
71921#endif /* DUK_USE_EXEC_PREFER_SIZE */
71922
71923 /* A -> target reg
71924 * B -> object reg/const (may be const e.g. in "'foo'[1]")
71925 * C -> key reg/const
71926 */
71927
71928 /* Opcode bits 0-1 are used to distinguish reg/const variants.
71929 * Opcode bits 2-3 are used to distinguish inc/dec variants:
71930 * Bit 2 = inc(0)/dec(1), bit 3 = pre(0)/post(1).
71931 */
71932 DUK_ASSERT((DUK_OP_PREINCP_RR & 0x0c) == 0x00);
71933 DUK_ASSERT((DUK_OP_PREDECP_RR & 0x0c) == 0x04);
71934 DUK_ASSERT((DUK_OP_POSTINCP_RR & 0x0c) == 0x08);
71935 DUK_ASSERT((DUK_OP_POSTDECP_RR & 0x0c) == 0x0c);
71936
71937 tv_obj = DUK__REGCONSTP_B(ins);
71938 tv_key = DUK__REGCONSTP_C(ins);
71939 rc = duk_hobject_getprop(thr, tv_obj, tv_key); /* -> [val] */
71940 DUK_UNREF(rc); /* ignore */
71941 tv_obj = NULL; /* invalidated */
71942 tv_key = NULL; /* invalidated */
71943
71944 /* XXX: Fastint fast path would be useful here. Also fastints
71945 * now lose their fastint status in current handling which is
71946 * not intuitive.
71947 */
71948
71949 x = duk_to_number_m1(ctx);
71950 duk_pop(ctx);
71951 if (ins & DUK_BC_INCDECP_FLAG_DEC) {
71952 y = x - 1.0;
71953 } else {
71954 y = x + 1.0;
71955 }
71956
71957 duk_push_number(ctx, y);
71958 tv_val = DUK_GET_TVAL_NEGIDX(ctx, -1);
71959 DUK_ASSERT(tv_val != NULL);
71960 tv_obj = DUK__REGCONSTP_B(ins);
71961 tv_key = DUK__REGCONSTP_C(ins);
71962 rc = duk_hobject_putprop(thr, tv_obj, tv_key, tv_val, DUK__STRICT());
71963 DUK_UNREF(rc); /* ignore */
71964 tv_obj = NULL; /* invalidated */
71965 tv_key = NULL; /* invalidated */
71966 duk_pop(ctx);
71967
71968 z = (ins & DUK_BC_INCDECP_FLAG_POST) ? x : y;
71969#if defined(DUK_USE_EXEC_PREFER_SIZE)
71970 duk_push_number(ctx, z);
71971 DUK__REPLACE_TOP_A_BREAK();
71972#else
71973 tv_dst = DUK__REGP_A(ins);
71974 DUK_TVAL_SET_NUMBER_UPDREF(thr, tv_dst, z);
71975 break;
71976#endif
71977 }
71978
71979 /* XXX: GETPROP where object is 'this', GETPROPT?
71980 * Occurs relatively often in object oriented code.
71981 */
71982
71983#define DUK__GETPROP_BODY(barg,carg) { \
71984 /* A -> target reg \
71985 * B -> object reg/const (may be const e.g. in "'foo'[1]") \
71986 * C -> key reg/const \
71987 */ \
71988 (void) duk_hobject_getprop(thr, (barg), (carg)); \
71989 DUK__REPLACE_TOP_A_BREAK(); \
71990 }
71991#define DUK__PUTPROP_BODY(aarg,barg,carg) { \
71992 /* A -> object reg \
71993 * B -> key reg/const \
71994 * C -> value reg/const \
71995 * \
71996 * Note: intentional difference to register arrangement \
71997 * of e.g. GETPROP; 'A' must contain a register-only value. \
71998 */ \
71999 (void) duk_hobject_putprop(thr, (aarg), (barg), (carg), DUK__STRICT()); \
72000 break; \
72001 }
72002#define DUK__DELPROP_BODY(barg,carg) { \
72003 /* A -> result reg \
72004 * B -> object reg \
72005 * C -> key reg/const \
72006 */ \
72007 duk_bool_t rc; \
72008 rc = duk_hobject_delprop(thr, (barg), (carg), DUK__STRICT()); \
72009 DUK_ASSERT(rc == 0 || rc == 1); \
72010 DUK__REPLACE_BOOL_A_BREAK(rc); \
72011 }
72012#if defined(DUK_USE_EXEC_PREFER_SIZE)
72013 case DUK_OP_GETPROP_RR:
72014 case DUK_OP_GETPROP_CR:
72015 case DUK_OP_GETPROP_RC:
72016 case DUK_OP_GETPROP_CC:
72017 DUK__GETPROP_BODY(DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
72018 case DUK_OP_PUTPROP_RR:
72019 case DUK_OP_PUTPROP_CR:
72020 case DUK_OP_PUTPROP_RC:
72021 case DUK_OP_PUTPROP_CC:
72022 DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__REGCONSTP_B(ins), DUK__REGCONSTP_C(ins));
72023 case DUK_OP_DELPROP_RR:
72024 case DUK_OP_DELPROP_RC: /* B is always reg */
72025 DUK__DELPROP_BODY(DUK__REGP_B(ins), DUK__REGCONSTP_C(ins));
72026#else /* DUK_USE_EXEC_PREFER_SIZE */
72027 case DUK_OP_GETPROP_RR:
72028 DUK__GETPROP_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
72029 case DUK_OP_GETPROP_CR:
72030 DUK__GETPROP_BODY(DUK__CONSTP_B(ins), DUK__REGP_C(ins));
72031 case DUK_OP_GETPROP_RC:
72032 DUK__GETPROP_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
72033 case DUK_OP_GETPROP_CC:
72034 DUK__GETPROP_BODY(DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
72035 case DUK_OP_PUTPROP_RR:
72036 DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__REGP_B(ins), DUK__REGP_C(ins));
72037 case DUK_OP_PUTPROP_CR:
72038 DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__CONSTP_B(ins), DUK__REGP_C(ins));
72039 case DUK_OP_PUTPROP_RC:
72040 DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__REGP_B(ins), DUK__CONSTP_C(ins));
72041 case DUK_OP_PUTPROP_CC:
72042 DUK__PUTPROP_BODY(DUK__REGP_A(ins), DUK__CONSTP_B(ins), DUK__CONSTP_C(ins));
72043 case DUK_OP_DELPROP_RR: /* B is always reg */
72044 DUK__DELPROP_BODY(DUK__REGP_B(ins), DUK__REGP_C(ins));
72045 case DUK_OP_DELPROP_RC:
72046 DUK__DELPROP_BODY(DUK__REGP_B(ins), DUK__CONSTP_C(ins));
72047#endif /* DUK_USE_EXEC_PREFER_SIZE */
72048
72049 /* No fast path for DECLVAR now, it's quite a rare instruction. */
72050 case DUK_OP_DECLVAR_RR:
72051 case DUK_OP_DECLVAR_CR:
72052 case DUK_OP_DECLVAR_RC:
72053 case DUK_OP_DECLVAR_CC: {
72054 duk_activation *act;
72055 duk_context *ctx = (duk_context *) thr;
72056 duk_small_uint_fast_t a = DUK_DEC_A(ins);
72057 duk_tval *tv1;
72058 duk_hstring *name;
72059 duk_small_uint_t prop_flags;
72060 duk_bool_t is_func_decl;
72061 duk_bool_t is_undef_value;
72062
72063 tv1 = DUK__REGCONSTP_B(ins);
72064 DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
72065 name = DUK_TVAL_GET_STRING(tv1);
72066 DUK_ASSERT(name != NULL);
72067
72068 is_undef_value = ((a & DUK_BC_DECLVAR_FLAG_UNDEF_VALUE) != 0);
72069 is_func_decl = ((a & DUK_BC_DECLVAR_FLAG_FUNC_DECL) != 0);
72070
72071 /* XXX: declvar takes an duk_tval pointer, which is awkward and
72072 * should be reworked.
72073 */
72074
72075 /* Compiler is responsible for selecting property flags (configurability,
72076 * writability, etc).
72077 */
72078 prop_flags = a & DUK_PROPDESC_FLAGS_MASK;
72079
72080 if (is_undef_value) {
72081 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* valstack policy */
72082 thr->valstack_top++;
72083 } else {
72084 duk_push_tval(ctx, DUK__REGCONSTP_C(ins));
72085 }
72086 tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1);
72087
72088 act = thr->callstack + thr->callstack_top - 1;
72089 if (duk_js_declvar_activation(thr, act, name, tv1, prop_flags, is_func_decl)) {
72090 /* already declared, must update binding value */
72091 tv1 = DUK_GET_TVAL_NEGIDX(ctx, -1);
72092 duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT());
72093 }
72094
72095 duk_pop(ctx);
72096 break;
72097 }
72098
72099#if defined(DUK_USE_REGEXP_SUPPORT)
72100 /* The compiler should never emit DUK_OP_REGEXP if there is no
72101 * regexp support.
72102 */
72103 case DUK_OP_REGEXP_RR:
72104 case DUK_OP_REGEXP_CR:
72105 case DUK_OP_REGEXP_RC:
72106 case DUK_OP_REGEXP_CC: {
72107 /* A -> target register
72108 * B -> bytecode (also contains flags)
72109 * C -> escaped source
72110 */
72111
72112 duk_push_tval((duk_context *) thr, DUK__REGCONSTP_C(ins));
72113 duk_push_tval((duk_context *) thr, DUK__REGCONSTP_B(ins)); /* -> [ ... escaped_source bytecode ] */
72114 duk_regexp_create_instance(thr); /* -> [ ... regexp_instance ] */
72115 DUK__REPLACE_TOP_A_BREAK();
72116 }
72117#endif /* DUK_USE_REGEXP_SUPPORT */
72118
72119 /* XXX: 'c' is unused, use whole BC, etc. */
72120 case DUK_OP_CSVAR_RR:
72121 case DUK_OP_CSVAR_CR:
72122 case DUK_OP_CSVAR_RC:
72123 case DUK_OP_CSVAR_CC: {
72124 /* The speciality of calling through a variable binding is that the
72125 * 'this' value may be provided by the variable lookup: E5 Section 6.b.i.
72126 *
72127 * The only (standard) case where the 'this' binding is non-null is when
72128 * (1) the variable is found in an object environment record, and
72129 * (2) that object environment record is a 'with' block.
72130 */
72131
72132 duk_context *ctx = (duk_context *) thr;
72133 duk_activation *act;
72134 duk_uint_fast_t idx;
72135 duk_tval *tv1;
72136 duk_hstring *name;
72137
72138 /* A -> target registers (A, A + 1) for call setup
72139 * B -> identifier name, usually constant but can be a register due to shuffling
72140 */
72141
72142 tv1 = DUK__REGCONSTP_B(ins);
72143 DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
72144 name = DUK_TVAL_GET_STRING(tv1);
72145 DUK_ASSERT(name != NULL);
72146 act = thr->callstack + thr->callstack_top - 1;
72147 (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */
72148
72149 idx = (duk_uint_fast_t) DUK_DEC_A(ins);
72150
72151 /* Could add direct value stack handling. */
72152 duk_replace(ctx, (duk_idx_t) (idx + 1)); /* 'this' binding */
72153 duk_replace(ctx, (duk_idx_t) idx); /* variable value (function, we hope, not checked here) */
72154 break;
72155 }
72156
72157 case DUK_OP_CLOSURE: {
72158 duk_activation *act;
72159 duk_hcompfunc *fun_act;
72160 duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
72161 duk_hobject *fun_temp;
72162
72163 /* A -> target reg
72164 * BC -> inner function index
72165 */
72166
72167 DUK_DDD(DUK_DDDPRINT("CLOSURE to target register %ld, fnum %ld (count %ld)",
72168 (long) DUK_DEC_A(ins), (long) DUK_DEC_BC(ins), (long) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, DUK__FUN())));
72169
72170 DUK_ASSERT_DISABLE(bc >= 0); /* unsigned */
72171 DUK_ASSERT((duk_uint_t) bc < (duk_uint_t) DUK_HCOMPFUNC_GET_FUNCS_COUNT(thr->heap, DUK__FUN()));
72172
72173 act = thr->callstack + thr->callstack_top - 1;
72174 fun_act = (duk_hcompfunc *) DUK_ACT_GET_FUNC(act);
72175 fun_temp = DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, fun_act)[bc];
72176 DUK_ASSERT(fun_temp != NULL);
72177 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(fun_temp));
72178
72179 DUK_DDD(DUK_DDDPRINT("CLOSURE: function template is: %p -> %!O",
72180 (void *) fun_temp, (duk_heaphdr *) fun_temp));
72181
72182 if (act->lex_env == NULL) {
72183 DUK_ASSERT(act->var_env == NULL);
72184 duk_js_init_activation_environment_records_delayed(thr, act);
72185 }
72186 DUK_ASSERT(act->lex_env != NULL);
72187 DUK_ASSERT(act->var_env != NULL);
72188
72189 /* functions always have a NEWENV flag, i.e. they get a
72190 * new variable declaration environment, so only lex_env
72191 * matters here.
72192 */
72193 duk_js_push_closure(thr,
72194 (duk_hcompfunc *) fun_temp,
72195 act->var_env,
72196 act->lex_env,
72197 1 /*add_auto_proto*/);
72198 DUK__REPLACE_TOP_A_BREAK();
72199 }
72200
72201 case DUK_OP_GETVAR: {
72202 duk_context *ctx = (duk_context *) thr;
72203 duk_activation *act;
72204 duk_tval *tv1;
72205 duk_hstring *name;
72206
72207 tv1 = DUK__CONSTP_BC(ins);
72208 DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
72209 name = DUK_TVAL_GET_STRING(tv1);
72210 DUK_ASSERT(name != NULL);
72211 act = thr->callstack + thr->callstack_top - 1;
72212 (void) duk_js_getvar_activation(thr, act, name, 1 /*throw*/); /* -> [... val this] */
72213 duk_pop(ctx); /* 'this' binding is not needed here */
72214 DUK__REPLACE_TOP_A_BREAK();
72215 }
72216
72217 case DUK_OP_PUTVAR: {
72218 duk_activation *act;
72219 duk_tval *tv1;
72220 duk_hstring *name;
72221
72222 tv1 = DUK__CONSTP_BC(ins);
72223 DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
72224 name = DUK_TVAL_GET_STRING(tv1);
72225 DUK_ASSERT(name != NULL);
72226
72227 /* XXX: putvar takes a duk_tval pointer, which is awkward and
72228 * should be reworked.
72229 */
72230
72231 tv1 = DUK__REGP_A(ins); /* val */
72232 act = thr->callstack + thr->callstack_top - 1;
72233 duk_js_putvar_activation(thr, act, name, tv1, DUK__STRICT());
72234 break;
72235 }
72236
72237 case DUK_OP_DELVAR: {
72238 duk_activation *act;
72239 duk_tval *tv1;
72240 duk_hstring *name;
72241 duk_bool_t rc;
72242
72243 tv1 = DUK__CONSTP_BC(ins);
72244 DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
72245 name = DUK_TVAL_GET_STRING(tv1);
72246 DUK_ASSERT(name != NULL);
72247 act = thr->callstack + thr->callstack_top - 1;
72248 rc = duk_js_delvar_activation(thr, act, name);
72249 DUK__REPLACE_BOOL_A_BREAK(rc);
72250 }
72251
72252 case DUK_OP_JUMP: {
72253 /* Note: without explicit cast to signed, MSVC will
72254 * apparently generate a large positive jump when the
72255 * bias-corrected value would normally be negative.
72256 */
72257 curr_pc += (duk_int_fast_t) DUK_DEC_ABC(ins) - (duk_int_fast_t) DUK_BC_JUMP_BIAS;
72258 break;
72259 }
72260
72261#define DUK__RETURN_SHARED() do { \
72262 duk_small_uint_t ret_result; \
72263 /* duk__handle_return() is guaranteed never to throw, except \
72264 * for potential out-of-memory situations which will then \
72265 * propagate out of the executor longjmp handler. \
72266 */ \
72267 ret_result = duk__handle_return(thr, \
72268 entry_thread, \
72269 entry_callstack_top); \
72270 if (ret_result == DUK__RETHAND_RESTART) { \
72271 goto restart_execution; \
72272 } \
72273 DUK_ASSERT(ret_result == DUK__RETHAND_FINISHED); \
72274 return; \
72275 } while (0)
72276#if defined(DUK_USE_EXEC_PREFER_SIZE)
72277 case DUK_OP_RETREG:
72278 case DUK_OP_RETCONST:
72279 case DUK_OP_RETCONSTN:
72280 case DUK_OP_RETUNDEF: {
72281 /* BC -> return value reg/const */
72282
72283 DUK__SYNC_AND_NULL_CURR_PC();
72284
72285 if (op == DUK_OP_RETREG) {
72286 duk_push_tval((duk_context *) thr, DUK__REGP_BC(ins));
72287 } else if (op == DUK_OP_RETUNDEF) {
72288 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* valstack policy */
72289 thr->valstack_top++;
72290 } else {
72291 DUK_ASSERT(op == DUK_OP_RETCONST || op == DUK_OP_RETCONSTN);
72292 duk_push_tval((duk_context *) thr, DUK__CONSTP_BC(ins));
72293 }
72294
72295 DUK__RETURN_SHARED();
72296 }
72297#else /* DUK_USE_EXEC_PREFER_SIZE */
72298 case DUK_OP_RETREG: {
72299 duk_tval *tv;
72300
72301 DUK__SYNC_AND_NULL_CURR_PC();
72302 tv = DUK__REGP_BC(ins);
72303 DUK_TVAL_SET_TVAL(thr->valstack_top, tv);
72304 DUK_TVAL_INCREF(thr, tv);
72305 thr->valstack_top++;
72306 DUK__RETURN_SHARED();
72307 }
72308 case DUK_OP_RETCONST: {
72309 duk_tval *tv;
72310
72311 DUK__SYNC_AND_NULL_CURR_PC();
72312 tv = DUK__CONSTP_BC(ins);
72313 DUK_TVAL_SET_TVAL(thr->valstack_top, tv);
72314 DUK_TVAL_INCREF(thr, tv);
72315 thr->valstack_top++;
72316 DUK__RETURN_SHARED();
72317 }
72318 case DUK_OP_RETCONSTN: {
72319 duk_tval *tv;
72320
72321 DUK__SYNC_AND_NULL_CURR_PC();
72322 tv = DUK__CONSTP_BC(ins);
72323 DUK_TVAL_SET_TVAL(thr->valstack_top, tv);
72324 DUK_ASSERT(!DUK_TVAL_IS_HEAP_ALLOCATED(tv)); /* no INCREF for this constant */
72325 thr->valstack_top++;
72326 DUK__RETURN_SHARED();
72327 }
72328 case DUK_OP_RETUNDEF: {
72329 DUK__SYNC_AND_NULL_CURR_PC();
72330 thr->valstack_top++; /* value at valstack top is already undefined by valstack policy */
72331 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top));
72332 DUK__RETURN_SHARED();
72333 }
72334#endif /* DUK_USE_EXEC_PREFER_SIZE */
72335
72336 case DUK_OP_LABEL: {
72337 duk_catcher *cat;
72338 duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
72339
72340 /* allocate catcher and populate it (should be atomic) */
72341
72342 duk_hthread_catchstack_grow(thr);
72343 cat = thr->catchstack + thr->catchstack_top;
72344 thr->catchstack_top++;
72345
72346 cat->flags = DUK_CAT_TYPE_LABEL | (bc << DUK_CAT_LABEL_SHIFT);
72347 cat->callstack_index = thr->callstack_top - 1;
72348 cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */
72349 cat->idx_base = 0; /* unused for label */
72350 cat->h_varname = NULL;
72351
72352 DUK_DDD(DUK_DDDPRINT("LABEL catcher: flags=0x%08lx, callstack_index=%ld, pc_base=%ld, "
72353 "idx_base=%ld, h_varname=%!O, label_id=%ld",
72354 (long) cat->flags, (long) cat->callstack_index, (long) cat->pc_base,
72355 (long) cat->idx_base, (duk_heaphdr *) cat->h_varname, (long) DUK_CAT_GET_LABEL(cat)));
72356
72357 curr_pc += 2; /* skip jump slots */
72358 break;
72359 }
72360
72361 case DUK_OP_ENDLABEL: {
72362 duk_catcher *cat;
72363#if (defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)) || defined(DUK_USE_ASSERTIONS)
72364 duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
72365#endif
72366#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
72367 DUK_DDD(DUK_DDDPRINT("ENDLABEL %ld", (long) bc));
72368#endif
72369
72370 DUK_ASSERT(thr->catchstack_top >= 1);
72371
72372 cat = thr->catchstack + thr->catchstack_top - 1;
72373 DUK_UNREF(cat);
72374 DUK_ASSERT(DUK_CAT_GET_TYPE(cat) == DUK_CAT_TYPE_LABEL);
72375 DUK_ASSERT((duk_uint_fast_t) DUK_CAT_GET_LABEL(cat) == bc);
72376
72377 duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
72378 /* no need to unwind callstack */
72379 break;
72380 }
72381
72382 case DUK_OP_BREAK: {
72383 duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
72384
72385 DUK__SYNC_AND_NULL_CURR_PC();
72386 duk__handle_break_or_continue(thr, (duk_uint_t) bc, DUK_LJ_TYPE_BREAK);
72387 goto restart_execution;
72388 }
72389
72390 case DUK_OP_CONTINUE: {
72391 duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
72392
72393 DUK__SYNC_AND_NULL_CURR_PC();
72394 duk__handle_break_or_continue(thr, (duk_uint_t) bc, DUK_LJ_TYPE_CONTINUE);
72395 goto restart_execution;
72396 }
72397
72398 /* XXX: move to helper, too large to be inline here */
72399 case DUK_OP_TRYCATCH: {
72400 duk_context *ctx = (duk_context *) thr;
72401 duk_activation *act;
72402 duk_catcher *cat;
72403 duk_tval *tv1;
72404 duk_small_uint_fast_t a;
72405 duk_small_uint_fast_t bc;
72406
72407 /* A -> flags
72408 * BC -> reg_catch; base register for two registers used both during
72409 * trycatch setup and when catch is triggered
72410 *
72411 * If DUK_BC_TRYCATCH_FLAG_CATCH_BINDING set:
72412 * reg_catch + 0: catch binding variable name (string).
72413 * Automatic declarative environment is established for
72414 * the duration of the 'catch' clause.
72415 *
72416 * If DUK_BC_TRYCATCH_FLAG_WITH_BINDING set:
72417 * reg_catch + 0: with 'target value', which is coerced to
72418 * an object and then used as a bindind object for an
72419 * environment record. The binding is initialized here, for
72420 * the 'try' clause.
72421 *
72422 * Note that a TRYCATCH generated for a 'with' statement has no
72423 * catch or finally parts.
72424 */
72425
72426 /* XXX: TRYCATCH handling should be reworked to avoid creating
72427 * an explicit scope unless it is actually needed (e.g. function
72428 * instances or eval is executed inside the catch block). This
72429 * rework is not trivial because the compiler doesn't have an
72430 * intermediate representation. When the rework is done, the
72431 * opcode format can also be made more straightforward.
72432 */
72433
72434 /* XXX: side effect handling is quite awkward here */
72435
72436 DUK_DDD(DUK_DDDPRINT("TRYCATCH: reg_catch=%ld, have_catch=%ld, "
72437 "have_finally=%ld, catch_binding=%ld, with_binding=%ld (flags=0x%02lx)",
72438 (long) DUK_DEC_BC(ins),
72439 (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH ? 1 : 0),
72440 (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY ? 1 : 0),
72441 (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING ? 1 : 0),
72442 (long) (DUK_DEC_A(ins) & DUK_BC_TRYCATCH_FLAG_WITH_BINDING ? 1 : 0),
72443 (unsigned long) DUK_DEC_A(ins)));
72444
72445 a = DUK_DEC_A(ins);
72446 bc = DUK_DEC_BC(ins);
72447
72448 act = thr->callstack + thr->callstack_top - 1;
72449 DUK_ASSERT(thr->callstack_top >= 1);
72450
72451 /* 'with' target must be created first, in case we run out of memory */
72452 /* XXX: refactor out? */
72453
72454 if (a & DUK_BC_TRYCATCH_FLAG_WITH_BINDING) {
72455 DUK_DDD(DUK_DDDPRINT("need to initialize a with binding object"));
72456
72457 if (act->lex_env == NULL) {
72458 DUK_ASSERT(act->var_env == NULL);
72459 DUK_DDD(DUK_DDDPRINT("delayed environment initialization"));
72460
72461 /* must relookup act in case of side effects */
72462 duk_js_init_activation_environment_records_delayed(thr, act);
72463 act = thr->callstack + thr->callstack_top - 1;
72464 DUK_UNREF(act); /* 'act' is no longer accessed, scanbuild fix */
72465 }
72466 DUK_ASSERT(act->lex_env != NULL);
72467 DUK_ASSERT(act->var_env != NULL);
72468
72469 (void) duk_push_object_helper(ctx,
72470 DUK_HOBJECT_FLAG_EXTENSIBLE |
72471 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_OBJENV),
72472 -1); /* no prototype, updated below */
72473
72474 duk_push_tval(ctx, DUK__REGP(bc));
72475 duk_to_object(ctx, -1);
72476 duk_dup_top(ctx);
72477
72478 /* [ ... env target ] */
72479 /* [ ... env target target ] */
72480
72481 duk_xdef_prop_stridx_short(thr, -3, DUK_STRIDX_INT_TARGET, DUK_PROPDESC_FLAGS_NONE);
72482 duk_xdef_prop_stridx_short(thr, -2, DUK_STRIDX_INT_THIS, DUK_PROPDESC_FLAGS_NONE); /* always provideThis=true */
72483
72484 /* [ ... env ] */
72485
72486 DUK_DDD(DUK_DDDPRINT("environment for with binding: %!iT",
72487 (duk_tval *) duk_get_tval(ctx, -1)));
72488 }
72489
72490 /* allocate catcher and populate it (should be atomic) */
72491
72492 duk_hthread_catchstack_grow(thr);
72493 cat = thr->catchstack + thr->catchstack_top;
72494 DUK_ASSERT(thr->catchstack_top + 1 <= thr->catchstack_size);
72495 thr->catchstack_top++;
72496
72497 cat->flags = DUK_CAT_TYPE_TCF;
72498 cat->h_varname = NULL;
72499
72500 if (a & DUK_BC_TRYCATCH_FLAG_HAVE_CATCH) {
72501 cat->flags |= DUK_CAT_FLAG_CATCH_ENABLED;
72502 }
72503 if (a & DUK_BC_TRYCATCH_FLAG_HAVE_FINALLY) {
72504 cat->flags |= DUK_CAT_FLAG_FINALLY_ENABLED;
72505 }
72506 if (a & DUK_BC_TRYCATCH_FLAG_CATCH_BINDING) {
72507 DUK_DDD(DUK_DDDPRINT("catch binding flag set to catcher"));
72508 cat->flags |= DUK_CAT_FLAG_CATCH_BINDING_ENABLED;
72509 tv1 = DUK__REGP(bc);
72510 DUK_ASSERT(DUK_TVAL_IS_STRING(tv1));
72511
72512 /* borrowed reference; although 'tv1' comes from a register,
72513 * its value was loaded using LDCONST so the constant will
72514 * also exist and be reachable.
72515 */
72516 cat->h_varname = DUK_TVAL_GET_STRING(tv1);
72517 } else if (a & DUK_BC_TRYCATCH_FLAG_WITH_BINDING) {
72518 /* env created above to stack top */
72519 duk_hobject *new_env;
72520
72521 DUK_DDD(DUK_DDDPRINT("lexenv active flag set to catcher"));
72522 cat->flags |= DUK_CAT_FLAG_LEXENV_ACTIVE;
72523
72524 DUK_DDD(DUK_DDDPRINT("activating object env: %!iT",
72525 (duk_tval *) duk_get_tval(ctx, -1)));
72526 DUK_ASSERT(act->lex_env != NULL);
72527 new_env = DUK_GET_HOBJECT_NEGIDX(ctx, -1);
72528 DUK_ASSERT(new_env != NULL);
72529
72530 act = thr->callstack + thr->callstack_top - 1; /* relookup (side effects) */
72531 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, new_env, act->lex_env); /* side effects */
72532
72533 act = thr->callstack + thr->callstack_top - 1; /* relookup (side effects) */
72534 act->lex_env = new_env;
72535 DUK_HOBJECT_INCREF(thr, new_env);
72536 duk_pop(ctx);
72537 } else {
72538 ;
72539 }
72540
72541 /* Registers 'bc' and 'bc + 1' are written in longjmp handling
72542 * and if their previous values (which are temporaries) become
72543 * unreachable -and- have a finalizer, there'll be a function
72544 * call during error handling which is not supported now (GH-287).
72545 * Ensure that both 'bc' and 'bc + 1' have primitive values to
72546 * guarantee no finalizer calls in error handling. Scrubbing also
72547 * ensures finalizers for the previous values run here rather than
72548 * later. Error handling related values are also written to 'bc'
72549 * and 'bc + 1' but those values never become unreachable during
72550 * error handling, so there's no side effect problem even if the
72551 * error value has a finalizer.
72552 */
72553 duk_to_undefined(ctx, bc);
72554 duk_to_undefined(ctx, bc + 1);
72555
72556 cat = thr->catchstack + thr->catchstack_top - 1; /* relookup (side effects) */
72557 cat->callstack_index = thr->callstack_top - 1;
72558 cat->pc_base = (duk_instr_t *) curr_pc; /* pre-incremented, points to first jump slot */
72559 cat->idx_base = (duk_size_t) (thr->valstack_bottom - thr->valstack) + bc;
72560
72561 DUK_DDD(DUK_DDDPRINT("TRYCATCH catcher: flags=0x%08lx, callstack_index=%ld, pc_base=%ld, "
72562 "idx_base=%ld, h_varname=%!O",
72563 (unsigned long) cat->flags, (long) cat->callstack_index,
72564 (long) cat->pc_base, (long) cat->idx_base, (duk_heaphdr *) cat->h_varname));
72565
72566 curr_pc += 2; /* skip jump slots */
72567 break;
72568 }
72569
72570 case DUK_OP_ENDTRY: {
72571 duk_catcher *cat;
72572 duk_tval *tv1;
72573
72574 DUK_ASSERT(thr->catchstack_top >= 1);
72575 DUK_ASSERT(thr->callstack_top >= 1);
72576 DUK_ASSERT(thr->catchstack[thr->catchstack_top - 1].callstack_index == thr->callstack_top - 1);
72577
72578 cat = thr->catchstack + thr->catchstack_top - 1;
72579
72580 DUK_DDD(DUK_DDDPRINT("ENDTRY: clearing catch active flag (regardless of whether it was set or not)"));
72581 DUK_CAT_CLEAR_CATCH_ENABLED(cat);
72582
72583 if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
72584 DUK_DDD(DUK_DDDPRINT("ENDTRY: finally part is active, jump through 2nd jump slot with 'normal continuation'"));
72585
72586 tv1 = thr->valstack + cat->idx_base;
72587 DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
72588 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */
72589 tv1 = NULL;
72590
72591 tv1 = thr->valstack + cat->idx_base + 1;
72592 DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
72593 DUK_TVAL_SET_U32_UPDREF(thr, tv1, (duk_uint32_t) DUK_LJ_TYPE_NORMAL); /* side effects */
72594 tv1 = NULL;
72595
72596 DUK_CAT_CLEAR_FINALLY_ENABLED(cat);
72597 } else {
72598 DUK_DDD(DUK_DDDPRINT("ENDTRY: no finally part, dismantle catcher, jump through 2nd jump slot (to end of statement)"));
72599 duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
72600 /* no need to unwind callstack */
72601 }
72602
72603 curr_pc = cat->pc_base + 1;
72604 break;
72605 }
72606
72607 case DUK_OP_ENDCATCH: {
72608 duk_activation *act;
72609 duk_catcher *cat;
72610 duk_tval *tv1;
72611
72612 DUK_ASSERT(thr->catchstack_top >= 1);
72613 DUK_ASSERT(thr->callstack_top >= 1);
72614 DUK_ASSERT(thr->catchstack[thr->catchstack_top - 1].callstack_index == thr->callstack_top - 1);
72615
72616 cat = thr->catchstack + thr->catchstack_top - 1;
72617 DUK_ASSERT(!DUK_CAT_HAS_CATCH_ENABLED(cat)); /* cleared before entering catch part */
72618
72619 act = thr->callstack + thr->callstack_top - 1;
72620
72621 if (DUK_CAT_HAS_LEXENV_ACTIVE(cat)) {
72622 duk_hobject *prev_env;
72623
72624 /* 'with' binding has no catch clause, so can't be here unless a normal try-catch */
72625 DUK_ASSERT(DUK_CAT_HAS_CATCH_BINDING_ENABLED(cat));
72626 DUK_ASSERT(act->lex_env != NULL);
72627
72628 DUK_DDD(DUK_DDDPRINT("ENDCATCH: popping catcher part lexical environment"));
72629
72630 prev_env = act->lex_env;
72631 DUK_ASSERT(prev_env != NULL);
72632 act->lex_env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, prev_env);
72633 DUK_CAT_CLEAR_LEXENV_ACTIVE(cat);
72634 DUK_HOBJECT_DECREF(thr, prev_env); /* side effects */
72635 }
72636
72637 if (DUK_CAT_HAS_FINALLY_ENABLED(cat)) {
72638 DUK_DDD(DUK_DDDPRINT("ENDCATCH: finally part is active, jump through 2nd jump slot with 'normal continuation'"));
72639
72640 tv1 = thr->valstack + cat->idx_base;
72641 DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
72642 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv1); /* side effects */
72643 tv1 = NULL;
72644
72645 tv1 = thr->valstack + cat->idx_base + 1;
72646 DUK_ASSERT(tv1 >= thr->valstack && tv1 < thr->valstack_top);
72647 DUK_TVAL_SET_U32_UPDREF(thr, tv1, (duk_uint32_t) DUK_LJ_TYPE_NORMAL); /* side effects */
72648 tv1 = NULL;
72649
72650 DUK_CAT_CLEAR_FINALLY_ENABLED(cat);
72651 } else {
72652 DUK_DDD(DUK_DDDPRINT("ENDCATCH: no finally part, dismantle catcher, jump through 2nd jump slot (to end of statement)"));
72653 duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
72654 /* no need to unwind callstack */
72655 }
72656
72657 curr_pc = cat->pc_base + 1;
72658 break;
72659 }
72660
72661 case DUK_OP_ENDFIN: {
72662 duk_context *ctx = (duk_context *) thr;
72663 duk_catcher *cat;
72664 duk_tval *tv1;
72665 duk_small_uint_t cont_type;
72666 duk_small_uint_t ret_result;
72667
72668 /* Sync and NULL early. */
72669 DUK__SYNC_AND_NULL_CURR_PC();
72670
72671 DUK_ASSERT(thr->catchstack_top >= 1);
72672 DUK_ASSERT(thr->callstack_top >= 1);
72673 DUK_ASSERT(thr->catchstack[thr->catchstack_top - 1].callstack_index == thr->callstack_top - 1);
72674
72675 cat = thr->catchstack + thr->catchstack_top - 1;
72676
72677 /* CATCH flag may be enabled or disabled here; it may be enabled if
72678 * the statement has a catch block but the try block does not throw
72679 * an error.
72680 */
72681 DUK_ASSERT(!DUK_CAT_HAS_FINALLY_ENABLED(cat)); /* cleared before entering finally */
72682 /* XXX: assert idx_base */
72683
72684 DUK_DDD(DUK_DDDPRINT("ENDFIN: completion value=%!T, type=%!T",
72685 (duk_tval *) (thr->valstack + cat->idx_base + 0),
72686 (duk_tval *) (thr->valstack + cat->idx_base + 1)));
72687
72688 tv1 = thr->valstack + cat->idx_base + 1; /* type */
72689 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
72690 cont_type = (duk_small_uint_t) DUK_TVAL_GET_NUMBER(tv1);
72691
72692 switch (cont_type) {
72693 case DUK_LJ_TYPE_NORMAL: {
72694 DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with 'normal' (non-abrupt) completion -> "
72695 "dismantle catcher, resume execution after ENDFIN"));
72696 duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
72697 /* no need to unwind callstack */
72698 goto restart_execution;
72699 }
72700 case DUK_LJ_TYPE_RETURN: {
72701 DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with 'return' complation -> dismantle "
72702 "catcher, handle return, lj.value1=%!T", thr->valstack + cat->idx_base));
72703
72704 /* Not necessary to unwind catchstack: return handling will
72705 * do it. The finally flag of 'cat' is no longer set. The
72706 * catch flag may be set, but it's not checked by return handling.
72707 */
72708 DUK_ASSERT(!DUK_CAT_HAS_FINALLY_ENABLED(cat)); /* cleared before entering finally */
72709#if 0
72710 duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
72711#endif
72712
72713 duk_push_tval(ctx, thr->valstack + cat->idx_base);
72714 ret_result = duk__handle_return(thr,
72715 entry_thread,
72716 entry_callstack_top);
72717 if (ret_result == DUK__RETHAND_RESTART) {
72718 goto restart_execution;
72719 }
72720 DUK_ASSERT(ret_result == DUK__RETHAND_FINISHED);
72721
72722 DUK_DDD(DUK_DDDPRINT("exiting executor after ENDFIN and RETURN (pseudo) longjmp type"));
72723 return;
72724 }
72725 case DUK_LJ_TYPE_BREAK:
72726 case DUK_LJ_TYPE_CONTINUE: {
72727 duk_uint_t label_id;
72728 duk_small_uint_t lj_type;
72729
72730 /* Not necessary to unwind catchstack: break/continue
72731 * handling will do it. The finally flag of 'cat' is
72732 * no longer set. The catch flag may be set, but it's
72733 * not checked by break/continue handling.
72734 */
72735#if 0
72736 duk_hthread_catchstack_unwind(thr, thr->catchstack_top - 1);
72737#endif
72738
72739 tv1 = thr->valstack + cat->idx_base;
72740 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
72741#if defined(DUK_USE_FASTINT)
72742 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1));
72743 label_id = (duk_small_uint_t) DUK_TVAL_GET_FASTINT_U32(tv1);
72744#else
72745 label_id = (duk_small_uint_t) DUK_TVAL_GET_NUMBER(tv1);
72746#endif
72747 lj_type = cont_type;
72748 duk__handle_break_or_continue(thr, label_id, lj_type);
72749 goto restart_execution;
72750 }
72751 default: {
72752 DUK_DDD(DUK_DDDPRINT("ENDFIN: finally part finishing with abrupt completion, lj_type=%ld -> "
72753 "dismantle catcher, re-throw error",
72754 (long) cont_type));
72755
72756 duk_push_tval(ctx, thr->valstack + cat->idx_base);
72757
72758 duk_err_setup_heap_ljstate(thr, (duk_small_int_t) cont_type);
72759
72760 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */
72761 duk_err_longjmp(thr);
72762 DUK_UNREACHABLE();
72763 }
72764 }
72765
72766 /* Must restart in all cases because we NULLed thr->ptr_curr_pc. */
72767 DUK_UNREACHABLE();
72768 break;
72769 }
72770
72771 case DUK_OP_THROW: {
72772 duk_context *ctx = (duk_context *) thr;
72773 duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
72774
72775 /* Note: errors are augmented when they are created, not
72776 * when they are thrown. So, don't augment here, it would
72777 * break re-throwing for instance.
72778 */
72779
72780 /* Sync so that augmentation sees up-to-date activations, NULL
72781 * thr->ptr_curr_pc so that it's not used if side effects occur
72782 * in augmentation or longjmp handling.
72783 */
72784 DUK__SYNC_AND_NULL_CURR_PC();
72785
72786 duk_dup(ctx, (duk_idx_t) bc);
72787 DUK_DDD(DUK_DDDPRINT("THROW ERROR (BYTECODE): %!dT (before throw augment)",
72788 (duk_tval *) duk_get_tval(ctx, -1)));
72789#if defined(DUK_USE_AUGMENT_ERROR_THROW)
72790 duk_err_augment_error_throw(thr);
72791 DUK_DDD(DUK_DDDPRINT("THROW ERROR (BYTECODE): %!dT (after throw augment)",
72792 (duk_tval *) duk_get_tval(ctx, -1)));
72793#endif
72794
72795 duk_err_setup_heap_ljstate(thr, DUK_LJ_TYPE_THROW);
72796
72797 DUK_ASSERT(thr->heap->lj.jmpbuf_ptr != NULL); /* always in executor */
72798 duk_err_longjmp(thr);
72799 DUK_UNREACHABLE();
72800 break;
72801 }
72802
72803 case DUK_OP_CSREG: {
72804 /*
72805 * Assuming a register binds to a variable declared within this
72806 * function (a declarative binding), the 'this' for the call
72807 * setup is always 'undefined'. E5 Section 10.2.1.1.6.
72808 */
72809
72810 duk_small_uint_fast_t a = DUK_DEC_A(ins);
72811 duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
72812
72813 /* A -> register containing target function (not type checked here)
72814 * BC -> target registers (BC, BC + 1) for call setup
72815 */
72816
72817#if defined(DUK_USE_PREFER_SIZE)
72818 duk_dup((duk_context *) thr, a);
72819 duk_replace((duk_context *) thr, bc);
72820 duk_to_undefined((duk_context *) thr, bc + 1);
72821#else
72822 duk_tval *tv1;
72823 duk_tval *tv2;
72824 duk_tval *tv3;
72825 duk_tval tv_tmp1;
72826 duk_tval tv_tmp2;
72827
72828 tv1 = DUK__REGP(bc);
72829 tv2 = tv1 + 1;
72830 DUK_TVAL_SET_TVAL(&tv_tmp1, tv1);
72831 DUK_TVAL_SET_TVAL(&tv_tmp2, tv2);
72832 tv3 = DUK__REGP(a);
72833 DUK_TVAL_SET_TVAL(tv1, tv3);
72834 DUK_TVAL_INCREF(thr, tv1); /* no side effects */
72835 DUK_TVAL_SET_UNDEFINED(tv2); /* no need for incref */
72836 DUK_TVAL_DECREF(thr, &tv_tmp1);
72837 DUK_TVAL_DECREF(thr, &tv_tmp2);
72838#endif
72839 break;
72840 }
72841
72842 case DUK_OP_EVALCALL: {
72843 /* Eval call or a normal call made using the identifier 'eval'.
72844 * Eval calls are never handled as tail calls for simplicity.
72845 */
72846 duk_context *ctx = (duk_context *) thr;
72847 duk_small_uint_fast_t nargs;
72848 duk_uint_fast_t idx;
72849 duk_idx_t num_stack_args;
72850 duk_small_uint_t call_flags;
72851 duk_tval *tv_func;
72852 duk_hobject *obj_func;
72853#if !defined(DUK_USE_EXEC_FUN_LOCAL)
72854 duk_hcompfunc *fun;
72855#endif
72856
72857 /* Technically we should also check for the possibility of
72858 * a pure Ecmascript-to-Ecmascript call: while built-in eval()
72859 * is native, it's possible for the 'eval' identifier to be
72860 * shadowed. In practice that would be rare and optimizing the
72861 * C call stack for that case is a bit pointless.
72862 */
72863
72864 nargs = (duk_small_uint_fast_t) DUK_DEC_A(ins);
72865 idx = (duk_uint_fast_t) DUK_DEC_BC(ins);
72866 duk_set_top(ctx, (duk_idx_t) (idx + nargs + 2)); /* [ ... func this arg1 ... argN ] */
72867
72868 call_flags = 0;
72869 tv_func = DUK_GET_TVAL_POSIDX(ctx, idx);
72870 if (DUK_TVAL_IS_OBJECT(tv_func)) {
72871 obj_func = DUK_TVAL_GET_OBJECT(tv_func);
72872 DUK_ASSERT(obj_func != NULL);
72873 if (DUK_HOBJECT_IS_NATFUNC(obj_func) &&
72874 ((duk_hnatfunc *) obj_func)->func == duk_bi_global_object_eval) {
72875 DUK_DDD(DUK_DDDPRINT("call target is eval, call identifier was 'eval' -> direct eval"));
72876 call_flags |= DUK_CALL_FLAG_DIRECT_EVAL;
72877 }
72878 }
72879 num_stack_args = nargs;
72880 duk_handle_call_unprotected(thr, num_stack_args, call_flags);
72881
72882#if !defined(DUK_USE_EXEC_FUN_LOCAL)
72883 fun = DUK__FUN();
72884#endif
72885 duk_set_top(ctx, (duk_idx_t) fun->nregs);
72886 break;
72887 }
72888
72889 case DUK_OP_CALL:
72890 case DUK_OP_TAILCALL: {
72891 /* DUK_OP_CALL: plain call, not tailcall compatible.
72892 *
72893 * DUK_OP_TAILCALL: plain call which is tailcall
72894 * compatible. Tail call may not be possible due
72895 * to e.g. target not being an Ecmascript function.
72896 *
72897 * Not a direct eval call. Indirect eval calls don't
72898 * need special handling here.
72899 */
72900
72901 /* To determine whether to use an optimized Ecmascript-to-Ecmascript
72902 * call, we need to know whether the final, non-bound function is an
72903 * Ecmascript function. Current implementation is to first try an
72904 * Ecma-to-Ecma call setup which also resolves the bound function
72905 * chain. The setup attempt overwrites call target at DUK__REGP(idx)
72906 * and may also fudge the argument list. However, it won't resolve
72907 * the effective 'this' binding if the setup fails. This is somewhat
72908 * awkward, and the two call setup code paths should be merged.
72909 *
72910 * If an Ecma-to-Ecma call is not possible, the actual call handling
72911 * will do another (unnecessary) attempt to resolve the bound function.
72912 */
72913
72914 duk_context *ctx = (duk_context *) thr;
72915 duk_small_uint_fast_t nargs;
72916 duk_uint_fast_t idx;
72917 duk_idx_t num_stack_args;
72918 duk_small_uint_t call_flags;
72919#if !defined(DUK_USE_EXEC_FUN_LOCAL)
72920 duk_hcompfunc *fun;
72921#endif
72922
72923 /* A -> nargs
72924 * BC -> base register for call (base -> func, base+1 -> this, base+2 -> arg1 ... base+2+N-1 -> argN)
72925 */
72926
72927 /* XXX: in some cases it's faster NOT to reuse the value
72928 * stack but rather copy the arguments on top of the stack
72929 * (mainly when the calling value stack is large and the value
72930 * stack resize would be large). See DUK_OP_NEW.
72931 */
72932
72933 nargs = (duk_small_uint_fast_t) DUK_DEC_A(ins);
72934 idx = (duk_uint_fast_t) DUK_DEC_BC(ins);
72935 duk_set_top(ctx, (duk_idx_t) (idx + nargs + 2)); /* [ ... func this arg1 ... argN ] */
72936
72937 /* DUK_OP_CALL and DUK_OP_TAILCALL are consecutive
72938 * which allows a simple bit test.
72939 */
72940 DUK_ASSERT((DUK_OP_CALL & 0x01) == 0);
72941 DUK_ASSERT((DUK_OP_TAILCALL & 0x01) == 1);
72942 call_flags = (ins & (1UL << DUK_BC_SHIFT_OP)) ? DUK_CALL_FLAG_IS_TAILCALL : 0;
72943
72944 num_stack_args = nargs;
72945 if (duk_handle_ecma_call_setup(thr, num_stack_args, call_flags)) {
72946 /* Ecma-to-ecma call possible, may or may not be a tail call.
72947 * Avoid C recursion by being clever.
72948 */
72949 DUK_DDD(DUK_DDDPRINT("ecma-to-ecma call setup possible, restart execution"));
72950 /* curr_pc synced by duk_handle_ecma_call_setup() */
72951 goto restart_execution;
72952 }
72953
72954 /* Recompute argument count: bound function handling may have shifted. */
72955 num_stack_args = duk_get_top(ctx) - (idx + 2);
72956 DUK_DDD(DUK_DDDPRINT("recomputed arg count: %ld\n", (long) num_stack_args));
72957
72958 /* Target is either a lightfunc or a function object.
72959 * We don't need to check for eval handling here: the
72960 * call may be an indirect eval ('myEval("something")')
72961 * but that requires no special handling.
72962 */
72963
72964 duk_handle_call_unprotected(thr, num_stack_args, 0 /*call_flags*/);
72965
72966 /* duk_js_call.c is required to restore the stack reserve
72967 * so we only need to reset the top.
72968 */
72969#if !defined(DUK_USE_EXEC_FUN_LOCAL)
72970 fun = DUK__FUN();
72971#endif
72972 duk_set_top(ctx, (duk_idx_t) fun->nregs);
72973
72974 /* No need to reinit setjmp() catchpoint, as call handling
72975 * will store and restore our state.
72976 */
72977
72978 /* When debugger is enabled, we need to recheck the activation
72979 * status after returning. This is now handled by call handling
72980 * and heap->dbg_force_restart.
72981 */
72982 break;
72983 }
72984
72985 case DUK_OP_NEW: {
72986 duk_context *ctx = (duk_context *) thr;
72987 duk_small_uint_fast_t a = DUK_DEC_A(ins);
72988 duk_small_uint_fast_t bc = DUK_DEC_BC(ins);
72989#if defined(DUK_USE_EXEC_PREFER_SIZE)
72990#if !defined(DUK_USE_EXEC_FUN_LOCAL)
72991 duk_hcompfunc *fun;
72992#endif
72993#else
72994 duk_small_uint_fast_t count;
72995 duk_tval *tv_src;
72996#endif
72997
72998 /* A -> num args (N)
72999 * BC -> target register and start reg: constructor, arg1, ..., argN
73000 */
73001
73002 /* duk_new() will call the constuctor using duk_handle_call().
73003 * A constructor call prevents a yield from inside the constructor,
73004 * even if the constructor is an Ecmascript function.
73005 */
73006
73007 /* Don't need to sync curr_pc here; duk_new() will do that
73008 * when it augments the created error.
73009 */
73010
73011#if defined(DUK_USE_EXEC_PREFER_SIZE)
73012 /* This alternative relies on our being allowed to trash anything
73013 * above 'bc' so we can just reuse the argument registers which
73014 * means smaller value stack use. Footprint is a bit smaller.
73015 */
73016 duk_set_top(ctx, (duk_idx_t) (bc + a + 1));
73017 duk_new(ctx, (duk_idx_t) a); /* [... constructor arg1 ... argN] -> [retval] */
73018
73019 /* The return value is already in its correct place at the stack,
73020 * i.e. it has replaced the 'constructor' at index bc. Just reset
73021 * top and we're done.
73022 */
73023
73024#if !defined(DUK_USE_EXEC_FUN_LOCAL)
73025 fun = DUK__FUN();
73026#endif
73027 duk_set_top(ctx, (duk_idx_t) fun->nregs);
73028#else /* DUK_USE_EXEC_PREFER_SIZE */
73029 /* Faster alternative is to duplicate the values to avoid a resize.
73030 * This depends on the relative size between the value stack and
73031 * the argument count, though.
73032 */
73033 count = a + 1;
73034 duk_require_stack(ctx, count);
73035 tv_src = DUK_GET_TVAL_POSIDX(ctx, bc);
73036 duk__push_tvals_incref_only(thr, tv_src, count);
73037 duk_new(ctx, (duk_idx_t) a); /* [... constructor arg1 ... argN] -> [retval] */
73038 duk_replace(ctx, bc);
73039#endif /* DUK_USE_EXEC_PREFER_SIZE */
73040
73041 /* When debugger is enabled, we need to recheck the activation
73042 * status after returning. This is now handled by call handling
73043 * and heap->dbg_force_restart.
73044 */
73045 break;
73046 }
73047
73048 case DUK_OP_NEWOBJ: {
73049 duk_context *ctx = (duk_context *) thr;
73050 duk_push_object(ctx);
73051 DUK__REPLACE_TOP_BC_BREAK();
73052 }
73053
73054 case DUK_OP_NEWARR: {
73055 duk_context *ctx = (duk_context *) thr;
73056 duk_push_array(ctx);
73057 DUK__REPLACE_TOP_BC_BREAK();
73058 }
73059
73060 case DUK_OP_MPUTOBJ:
73061 case DUK_OP_MPUTOBJI: {
73062 duk_context *ctx = (duk_context *) thr;
73063 duk_idx_t obj_idx;
73064 duk_uint_fast_t idx, idx_end;
73065 duk_small_uint_fast_t count;
73066
73067 /* A -> register of target object
73068 * B -> first register of key/value pair list
73069 * or register containing first register number if indirect
73070 * C -> number of key/value pairs * 2
73071 * (= number of value stack indices used starting from 'B')
73072 */
73073
73074 obj_idx = DUK_DEC_A(ins);
73075 DUK_ASSERT(duk_is_object(ctx, obj_idx));
73076
73077 idx = (duk_uint_fast_t) DUK_DEC_B(ins);
73078 if (DUK_DEC_OP(ins) == DUK_OP_MPUTOBJI) {
73079 DUK__LOOKUP_INDIRECT_INDEX(idx);
73080 }
73081
73082 count = (duk_small_uint_fast_t) DUK_DEC_C(ins);
73083 DUK_ASSERT(count > 0); /* compiler guarantees */
73084 idx_end = idx + count;
73085
73086#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
73087 if (DUK_UNLIKELY(idx_end > (duk_uint_fast_t) duk_get_top(ctx))) {
73088 /* XXX: use duk_is_valid_index() instead? */
73089 /* XXX: improve check; check against nregs, not against top */
73090 DUK__INTERNAL_ERROR("MPUTOBJ out of bounds");
73091 }
73092#endif
73093
73094 /* Use 'force' flag to duk_def_prop() to ensure that any
73095 * inherited properties don't prevent the operation.
73096 * With ES2015 duplicate properties are allowed, so that we
73097 * must overwrite any previous data or accessor property.
73098 *
73099 * With ES2015 computed property names the literal keys
73100 * may be arbitrary values and need to be ToPropertyKey()
73101 * coerced at runtime.
73102 */
73103 do {
73104 /* XXX: faster initialization (direct access or better primitives) */
73105 duk_dup(ctx, idx);
73106 duk_dup(ctx, idx + 1);
73107 duk_def_prop(ctx, obj_idx, DUK_DEFPROP_HAVE_VALUE |
73108 DUK_DEFPROP_FORCE |
73109 DUK_DEFPROP_SET_WRITABLE |
73110 DUK_DEFPROP_SET_ENUMERABLE |
73111 DUK_DEFPROP_SET_CONFIGURABLE);
73112 idx += 2;
73113 } while (idx < idx_end);
73114 break;
73115 }
73116
73117 case DUK_OP_INITSET:
73118 case DUK_OP_INITGET: {
73119 duk_context *ctx = (duk_context *) thr;
73120 duk_bool_t is_set = (op == DUK_OP_INITSET);
73121 duk_uint_fast_t idx;
73122 duk_uint_t defprop_flags;
73123
73124 /* A -> object register (acts as a source)
73125 * BC -> BC+0 contains key, BC+1 closure (value)
73126 */
73127
73128 /* INITSET/INITGET are only used to initialize object literal keys.
73129 * There may be a previous propery in ES2015 because duplicate property
73130 * names are allowed.
73131 */
73132
73133 /* This could be made more optimal by accessing internals directly. */
73134
73135 idx = (duk_uint_fast_t) DUK_DEC_BC(ins);
73136 duk_dup(ctx, (duk_idx_t) (idx + 0)); /* key */
73137 duk_dup(ctx, (duk_idx_t) (idx + 1)); /* getter/setter */
73138 if (is_set) {
73139 defprop_flags = DUK_DEFPROP_HAVE_SETTER |
73140 DUK_DEFPROP_FORCE |
73141 DUK_DEFPROP_SET_ENUMERABLE |
73142 DUK_DEFPROP_SET_CONFIGURABLE;
73143 } else {
73144 defprop_flags = DUK_DEFPROP_HAVE_GETTER |
73145 DUK_DEFPROP_FORCE |
73146 DUK_DEFPROP_SET_ENUMERABLE |
73147 DUK_DEFPROP_SET_CONFIGURABLE;
73148 }
73149 duk_def_prop(ctx, (duk_idx_t) DUK_DEC_A(ins), defprop_flags);
73150 break;
73151 }
73152
73153 case DUK_OP_MPUTARR:
73154 case DUK_OP_MPUTARRI: {
73155 duk_context *ctx = (duk_context *) thr;
73156 duk_idx_t obj_idx;
73157 duk_uint_fast_t idx, idx_end;
73158 duk_small_uint_fast_t count;
73159 duk_tval *tv1;
73160 duk_uint32_t arr_idx;
73161
73162 /* A -> register of target object
73163 * B -> first register of value data (start_index, value1, value2, ..., valueN)
73164 * or register containing first register number if indirect
73165 * C -> number of key/value pairs (N)
73166 */
73167
73168 obj_idx = DUK_DEC_A(ins);
73169 DUK_ASSERT(duk_is_object(ctx, obj_idx));
73170
73171 idx = (duk_uint_fast_t) DUK_DEC_B(ins);
73172 if (DUK_DEC_OP(ins) == DUK_OP_MPUTARRI) {
73173 DUK__LOOKUP_INDIRECT_INDEX(idx);
73174 }
73175
73176 count = (duk_small_uint_fast_t) DUK_DEC_C(ins);
73177 DUK_ASSERT(count > 0 + 1); /* compiler guarantees */
73178 idx_end = idx + count;
73179
73180#if defined(DUK_USE_EXEC_INDIRECT_BOUND_CHECK)
73181 if (idx_end > (duk_uint_fast_t) duk_get_top(ctx)) {
73182 /* XXX: use duk_is_valid_index() instead? */
73183 /* XXX: improve check; check against nregs, not against top */
73184 DUK__INTERNAL_ERROR("MPUTARR out of bounds");
73185 }
73186#endif
73187
73188 tv1 = DUK__REGP(idx);
73189 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
73190#if defined(DUK_USE_FASTINT)
73191 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1));
73192 arr_idx = (duk_uint32_t) DUK_TVAL_GET_FASTINT_U32(tv1);
73193#else
73194 arr_idx = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv1);
73195#endif
73196 idx++;
73197
73198 do {
73199 /* duk_xdef_prop() will define an own property without any array
73200 * special behaviors. We'll need to set the array length explicitly
73201 * in the end. For arrays with elisions, the compiler will emit an
73202 * explicit SETALEN which will update the length.
73203 */
73204
73205 /* XXX: because we're dealing with 'own' properties of a fresh array,
73206 * the array initializer should just ensure that the array has a large
73207 * enough array part and write the values directly into array part,
73208 * and finally set 'length' manually in the end (as already happens now).
73209 */
73210
73211 duk_dup(ctx, idx);
73212 duk_xdef_prop_index_wec(ctx, obj_idx, arr_idx);
73213
73214 idx++;
73215 arr_idx++;
73216 } while (idx < idx_end);
73217
73218 /* XXX: E5.1 Section 11.1.4 coerces the final length through
73219 * ToUint32() which is odd but happens now as a side effect of
73220 * 'arr_idx' type.
73221 */
73222 duk_set_length(thr, obj_idx, (duk_size_t) (duk_uarridx_t) arr_idx);
73223 break;
73224 }
73225
73226 case DUK_OP_SETALEN: {
73227 duk_tval *tv1;
73228 duk_hobject *h;
73229 duk_uint32_t len;
73230
73231 tv1 = DUK__REGP_A(ins);
73232 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv1));
73233 h = DUK_TVAL_GET_OBJECT(tv1);
73234 DUK_ASSERT(DUK_HOBJECT_IS_ARRAY(h));
73235
73236 tv1 = DUK__REGP_BC(ins);
73237 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv1));
73238#if defined(DUK_USE_FASTINT)
73239 DUK_ASSERT(DUK_TVAL_IS_FASTINT(tv1));
73240 len = (duk_uint32_t) DUK_TVAL_GET_FASTINT_U32(tv1);
73241#else
73242 len = (duk_uint32_t) DUK_TVAL_GET_NUMBER(tv1);
73243#endif
73244 ((duk_harray *) h)->length = len;
73245 break;
73246 }
73247
73248 case DUK_OP_INITENUM: {
73249 duk_context *ctx = (duk_context *) thr;
73250 duk_small_uint_fast_t b = DUK_DEC_B(ins);
73251 duk_small_uint_fast_t c = DUK_DEC_C(ins);
73252
73253 /*
73254 * Enumeration semantics come from for-in statement, E5 Section 12.6.4.
73255 * If called with 'null' or 'undefined', this opcode returns 'null' as
73256 * the enumerator, which is special cased in NEXTENUM. This simplifies
73257 * the compiler part
73258 */
73259
73260 /* B -> register for writing enumerator object
73261 * C -> value to be enumerated (register)
73262 */
73263
73264 if (duk_is_null_or_undefined(ctx, (duk_idx_t) c)) {
73265 duk_push_null(ctx);
73266 duk_replace(ctx, (duk_idx_t) b);
73267 } else {
73268 duk_dup(ctx, (duk_idx_t) c);
73269 duk_to_object(ctx, -1);
73270 duk_hobject_enumerator_create(ctx, 0 /*enum_flags*/); /* [ ... val ] --> [ ... enum ] */
73271 duk_replace(ctx, (duk_idx_t) b);
73272 }
73273 break;
73274 }
73275
73276 case DUK_OP_NEXTENUM: {
73277 duk_context *ctx = (duk_context *) thr;
73278 duk_small_uint_fast_t b = DUK_DEC_B(ins);
73279 duk_small_uint_fast_t c = DUK_DEC_C(ins);
73280
73281 /*
73282 * NEXTENUM checks whether the enumerator still has unenumerated
73283 * keys. If so, the next key is loaded to the target register
73284 * and the next instruction is skipped. Otherwise the next instruction
73285 * will be executed, jumping out of the enumeration loop.
73286 */
73287
73288 /* B -> target register for next key
73289 * C -> enum register
73290 */
73291
73292 DUK_DDD(DUK_DDDPRINT("NEXTENUM: b->%!T, c->%!T",
73293 (duk_tval *) duk_get_tval(ctx, (duk_idx_t) b),
73294 (duk_tval *) duk_get_tval(ctx, (duk_idx_t) c)));
73295
73296 if (duk_is_object(ctx, (duk_idx_t) c)) {
73297 /* XXX: assert 'c' is an enumerator */
73298 duk_dup(ctx, (duk_idx_t) c);
73299 if (duk_hobject_enumerator_next(ctx, 0 /*get_value*/)) {
73300 /* [ ... enum ] -> [ ... next_key ] */
73301 DUK_DDD(DUK_DDDPRINT("enum active, next key is %!T, skip jump slot ",
73302 (duk_tval *) duk_get_tval(ctx, -1)));
73303 curr_pc++;
73304 } else {
73305 /* [ ... enum ] -> [ ... ] */
73306 DUK_DDD(DUK_DDDPRINT("enum finished, execute jump slot"));
73307 DUK_ASSERT(DUK_TVAL_IS_UNDEFINED(thr->valstack_top)); /* valstack policy */
73308 thr->valstack_top++;
73309 }
73310 duk_replace(ctx, (duk_idx_t) b);
73311 } else {
73312 /* 'null' enumerator case -> behave as with an empty enumerator */
73313 DUK_ASSERT(duk_is_null(ctx, (duk_idx_t) c));
73314 DUK_DDD(DUK_DDDPRINT("enum is null, execute jump slot"));
73315 }
73316 break;
73317 }
73318
73319 case DUK_OP_INVLHS: {
73320 DUK_ERROR_REFERENCE(thr, DUK_STR_INVALID_LVALUE);
73321 DUK_UNREACHABLE();
73322 break;
73323 }
73324
73325 case DUK_OP_DEBUGGER: {
73326 /* Opcode only emitted by compiler when debugger
73327 * support is enabled. Ignore it silently without
73328 * debugger support, in case it has been loaded
73329 * from precompiled bytecode.
73330 */
73331#if defined(DUK_USE_DEBUGGER_SUPPORT)
73332 if (DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) {
73333 DUK_D(DUK_DPRINT("DEBUGGER statement encountered, halt execution"));
73334 DUK__SYNC_AND_NULL_CURR_PC();
73335 duk_debug_halt_execution(thr, 1 /*use_prev_pc*/);
73336 DUK_D(DUK_DPRINT("DEBUGGER statement finished, resume execution"));
73337 goto restart_execution;
73338 } else {
73339 DUK_D(DUK_DPRINT("DEBUGGER statement ignored, debugger not attached"));
73340 }
73341#else
73342 DUK_D(DUK_DPRINT("DEBUGGER statement ignored, no debugger support"));
73343#endif
73344 break;
73345 }
73346
73347 case DUK_OP_NOP: {
73348 /* nop */
73349 break;
73350 }
73351
73352 case DUK_OP_INVALID: {
73353 DUK_ERROR_FMT1(thr, DUK_ERR_ERROR, "INVALID opcode (%ld)", (long) DUK_DEC_ABC(ins));
73354 break;
73355 }
73356
73357#if !defined(DUK_USE_EXEC_PREFER_SIZE)
73358#if !defined(DUK_USE_ES7_EXP_OPERATOR)
73359 case DUK_OP_EXP_RR:
73360 case DUK_OP_EXP_CR:
73361 case DUK_OP_EXP_RC:
73362 case DUK_OP_EXP_CC:
73363#endif
73364 case DUK_OP_UNUSED194:
73365 case DUK_OP_UNUSED195:
73366 case DUK_OP_UNUSED196:
73367 case DUK_OP_UNUSED197:
73368 case DUK_OP_UNUSED198:
73369 case DUK_OP_UNUSED199:
73370 case DUK_OP_UNUSED200:
73371 case DUK_OP_UNUSED201:
73372 case DUK_OP_UNUSED202:
73373 case DUK_OP_UNUSED203:
73374 case DUK_OP_UNUSED204:
73375 case DUK_OP_UNUSED205:
73376 case DUK_OP_UNUSED206:
73377 case DUK_OP_UNUSED207:
73378 case DUK_OP_UNUSED208:
73379 case DUK_OP_UNUSED209:
73380 case DUK_OP_UNUSED210:
73381 case DUK_OP_UNUSED211:
73382 case DUK_OP_UNUSED212:
73383 case DUK_OP_UNUSED213:
73384 case DUK_OP_UNUSED214:
73385 case DUK_OP_UNUSED215:
73386 case DUK_OP_UNUSED216:
73387 case DUK_OP_UNUSED217:
73388 case DUK_OP_UNUSED218:
73389 case DUK_OP_UNUSED219:
73390 case DUK_OP_UNUSED220:
73391 case DUK_OP_UNUSED221:
73392 case DUK_OP_UNUSED222:
73393 case DUK_OP_UNUSED223:
73394 case DUK_OP_UNUSED224:
73395 case DUK_OP_UNUSED225:
73396 case DUK_OP_UNUSED226:
73397 case DUK_OP_UNUSED227:
73398 case DUK_OP_UNUSED228:
73399 case DUK_OP_UNUSED229:
73400 case DUK_OP_UNUSED230:
73401 case DUK_OP_UNUSED231:
73402 case DUK_OP_UNUSED232:
73403 case DUK_OP_UNUSED233:
73404 case DUK_OP_UNUSED234:
73405 case DUK_OP_UNUSED235:
73406 case DUK_OP_UNUSED236:
73407 case DUK_OP_UNUSED237:
73408 case DUK_OP_UNUSED238:
73409 case DUK_OP_UNUSED239:
73410 case DUK_OP_UNUSED240:
73411 case DUK_OP_UNUSED241:
73412 case DUK_OP_UNUSED242:
73413 case DUK_OP_UNUSED243:
73414 case DUK_OP_UNUSED244:
73415 case DUK_OP_UNUSED245:
73416 case DUK_OP_UNUSED246:
73417 case DUK_OP_UNUSED247:
73418 case DUK_OP_UNUSED248:
73419 case DUK_OP_UNUSED249:
73420 case DUK_OP_UNUSED250:
73421 case DUK_OP_UNUSED251:
73422 case DUK_OP_UNUSED252:
73423 case DUK_OP_UNUSED253:
73424 case DUK_OP_UNUSED254:
73425 case DUK_OP_UNUSED255: {
73426 /* Force all case clauses to map to an actual handler
73427 * so that the compiler can emit a jump without a bounds
73428 * check: the switch argument is a duk_uint8_t so that
73429 * the compiler may be able to figure it out. This is
73430 * a small detail and obviously compiler dependent.
73431 */
73432 volatile duk_small_int_t dummy_volatile;
73433 dummy_volatile = 0;
73434 DUK_UNREF(dummy_volatile);
73435 DUK_D(DUK_DPRINT("invalid opcode: %ld - %!I", (long) op, ins));
73436 DUK__INTERNAL_ERROR("invalid opcode");
73437 break;
73438 }
73439#endif /* DUK_USE_EXEC_PREFER_SIZE */
73440 default: {
73441 /* Default case catches invalid/unsupported opcodes. */
73442 DUK_D(DUK_DPRINT("invalid opcode: %ld - %!I", (long) op, ins));
73443 DUK__INTERNAL_ERROR("invalid opcode");
73444 break;
73445 }
73446
73447 } /* end switch */
73448
73449 continue;
73450
73451 /* Some shared exit paths for opcode handling below. These
73452 * are mostly useful to reduce code footprint when multiple
73453 * opcodes have a similar epilogue (like replacing stack top
73454 * with index 'a').
73455 */
73456
73457#if defined(DUK_USE_EXEC_PREFER_SIZE)
73458 replace_top_a:
73459 DUK__REPLACE_TO_TVPTR(thr, DUK__REGP_A(ins));
73460 continue;
73461 replace_top_bc:
73462 DUK__REPLACE_TO_TVPTR(thr, DUK__REGP_BC(ins));
73463 continue;
73464#endif
73465 }
73466 DUK_UNREACHABLE();
73467
73468#if !defined(DUK_USE_VERBOSE_EXECUTOR_ERRORS)
73469 internal_error:
73470 DUK_ERROR_INTERNAL(thr);
73471#endif
73472}
73473
73474/* automatic undefs */
73475#undef DUK__BYTEOFF_A
73476#undef DUK__BYTEOFF_B
73477#undef DUK__BYTEOFF_BC
73478#undef DUK__BYTEOFF_C
73479#undef DUK__COMPARE_BODY
73480#undef DUK__CONST
73481#undef DUK__CONSTP
73482#undef DUK__CONSTP_A
73483#undef DUK__CONSTP_B
73484#undef DUK__CONSTP_BC
73485#undef DUK__CONSTP_C
73486#undef DUK__DELPROP_BODY
73487#undef DUK__EQ_BODY
73488#undef DUK__FUN
73489#undef DUK__GETPROP_BODY
73490#undef DUK__GE_BODY
73491#undef DUK__GT_BODY
73492#undef DUK__INLINE_PERF
73493#undef DUK__INSTOF_BODY
73494#undef DUK__INTERNAL_ERROR
73495#undef DUK__INT_NOACTION
73496#undef DUK__INT_RESTART
73497#undef DUK__IN_BODY
73498#undef DUK__LE_BODY
73499#undef DUK__LONGJMP_RESTART
73500#undef DUK__LONGJMP_RETHROW
73501#undef DUK__LOOKUP_INDIRECT_INDEX
73502#undef DUK__LT_BODY
73503#undef DUK__MASK_A
73504#undef DUK__MASK_B
73505#undef DUK__MASK_BC
73506#undef DUK__MASK_C
73507#undef DUK__NEQ_BODY
73508#undef DUK__PUTPROP_BODY
73509#undef DUK__RCBIT_B
73510#undef DUK__RCBIT_C
73511#undef DUK__REG
73512#undef DUK__REGCONSTP_B
73513#undef DUK__REGCONSTP_C
73514#undef DUK__REGP
73515#undef DUK__REGP_A
73516#undef DUK__REGP_B
73517#undef DUK__REGP_BC
73518#undef DUK__REGP_C
73519#undef DUK__REPLACE_BOOL_A_BREAK
73520#undef DUK__REPLACE_TOP_A_BREAK
73521#undef DUK__REPLACE_TOP_BC_BREAK
73522#undef DUK__REPLACE_TO_TVPTR
73523#undef DUK__RETHAND_FINISHED
73524#undef DUK__RETHAND_RESTART
73525#undef DUK__RETURN_SHARED
73526#undef DUK__SEQ_BODY
73527#undef DUK__SHIFT_A
73528#undef DUK__SHIFT_B
73529#undef DUK__SHIFT_BC
73530#undef DUK__SHIFT_C
73531#undef DUK__SNEQ_BODY
73532#undef DUK__STRICT
73533#undef DUK__SYNC_AND_NULL_CURR_PC
73534#undef DUK__SYNC_CURR_PC
73535#undef DUK__TVAL_SHIFT
73536/*
73537 * Ecmascript specification algorithm and conversion helpers.
73538 *
73539 * These helpers encapsulate the primitive Ecmascript operation semantics,
73540 * and are used by the bytecode executor and the API (among other places).
73541 * Some primitives are only implemented as part of the API and have no
73542 * "internal" helper. This is the case when an internal helper would not
73543 * really be useful; e.g. the operation is rare, uses value stack heavily,
73544 * etc.
73545 *
73546 * The operation arguments depend on what is required to implement
73547 * the operation:
73548 *
73549 * - If an operation is simple and stateless, and has no side
73550 * effects, it won't take an duk_hthread argument and its
73551 * arguments may be duk_tval pointers (which are safe as long
73552 * as no side effects take place).
73553 *
73554 * - If complex coercions are required (e.g. a "ToNumber" coercion)
73555 * or errors may be thrown, the operation takes an duk_hthread
73556 * argument. This also implies that the operation may have
73557 * arbitrary side effects, invalidating any duk_tval pointers.
73558 *
73559 * - For operations with potential side effects, arguments can be
73560 * taken in several ways:
73561 *
73562 * a) as duk_tval pointers, which makes sense if the "common case"
73563 * can be resolved without side effects (e.g. coercion); the
73564 * arguments are pushed to the valstack for coercion if
73565 * necessary
73566 *
73567 * b) as duk_tval values
73568 *
73569 * c) implicitly on value stack top
73570 *
73571 * d) as indices to the value stack
73572 *
73573 * Future work:
73574 *
73575 * - Argument styles may not be the most sensible in every case now.
73576 *
73577 * - In-place coercions might be useful for several operations, if
73578 * in-place coercion is OK for the bytecode executor and the API.
73579 */
73580
73581/* #include duk_internal.h -> already included */
73582
73583/*
73584 * ToPrimitive() (E5 Section 9.1)
73585 *
73586 * ==> implemented in the API.
73587 */
73588
73589/*
73590 * ToBoolean() (E5 Section 9.2)
73591 */
73592
73593DUK_INTERNAL duk_bool_t duk_js_toboolean(duk_tval *tv) {
73594 switch (DUK_TVAL_GET_TAG(tv)) {
73595 case DUK_TAG_UNDEFINED:
73596 case DUK_TAG_NULL:
73597 return 0;
73598 case DUK_TAG_BOOLEAN:
73599 DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv) == 0 || DUK_TVAL_GET_BOOLEAN(tv) == 1);
73600 return DUK_TVAL_GET_BOOLEAN(tv);
73601 case DUK_TAG_STRING: {
73602 /* Symbols ToBoolean() coerce to true, regardless of their
73603 * description. This happens with no explicit check because
73604 * of the symbol representation byte prefix.
73605 */
73606 duk_hstring *h = DUK_TVAL_GET_STRING(tv);
73607 DUK_ASSERT(h != NULL);
73608 return (DUK_HSTRING_GET_BYTELEN(h) > 0 ? 1 : 0);
73609 }
73610 case DUK_TAG_OBJECT: {
73611 return 1;
73612 }
73613 case DUK_TAG_BUFFER: {
73614 /* Mimic Uint8Array semantics: objects coerce true, regardless
73615 * of buffer length (zero or not) or context.
73616 */
73617 return 1;
73618 }
73619 case DUK_TAG_POINTER: {
73620 void *p = DUK_TVAL_GET_POINTER(tv);
73621 return (p != NULL ? 1 : 0);
73622 }
73623 case DUK_TAG_LIGHTFUNC: {
73624 return 1;
73625 }
73626#if defined(DUK_USE_FASTINT)
73627 case DUK_TAG_FASTINT:
73628 if (DUK_TVAL_GET_FASTINT(tv) != 0) {
73629 return 1;
73630 } else {
73631 return 0;
73632 }
73633#endif
73634 default: {
73635 /* number */
73636 duk_double_t d;
73637#if defined(DUK_USE_PREFER_SIZE)
73638 int c;
73639#endif
73640 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
73641 DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
73642 d = DUK_TVAL_GET_DOUBLE(tv);
73643#if defined(DUK_USE_PREFER_SIZE)
73644 c = DUK_FPCLASSIFY((double) d);
73645 if (c == DUK_FP_ZERO || c == DUK_FP_NAN) {
73646 return 0;
73647 } else {
73648 return 1;
73649 }
73650#else
73651 DUK_ASSERT(duk_double_is_nan_or_zero(d) == 0 || duk_double_is_nan_or_zero(d) == 1);
73652 return duk_double_is_nan_or_zero(d) ^ 1;
73653#endif
73654 }
73655 }
73656 DUK_UNREACHABLE();
73657}
73658
73659/*
73660 * ToNumber() (E5 Section 9.3)
73661 *
73662 * Value to convert must be on stack top, and is popped before exit.
73663 *
73664 * See: http://www.cs.indiana.edu/~burger/FP-Printing-PLDI96.pdf
73665 * http://www.cs.indiana.edu/~burger/fp/index.html
73666 *
73667 * Notes on the conversion:
73668 *
73669 * - There are specific requirements on the accuracy of the conversion
73670 * through a "Mathematical Value" (MV), so this conversion is not
73671 * trivial.
73672 *
73673 * - Quick rejects (e.g. based on first char) are difficult because
73674 * the grammar allows leading and trailing white space.
73675 *
73676 * - Quick reject based on string length is difficult even after
73677 * accounting for white space; there may be arbitrarily many
73678 * decimal digits.
73679 *
73680 * - Standard grammar allows decimal values ("123"), hex values
73681 * ("0x123") and infinities
73682 *
73683 * - Unlike source code literals, ToNumber() coerces empty strings
73684 * and strings with only whitespace to zero (not NaN).
73685 */
73686
73687/* E5 Section 9.3.1 */
73688DUK_LOCAL duk_double_t duk__tonumber_string_raw(duk_hthread *thr) {
73689 duk_context *ctx = (duk_context *) thr;
73690 duk_small_uint_t s2n_flags;
73691 duk_double_t d;
73692
73693 DUK_ASSERT(duk_is_string(ctx, -1));
73694
73695 /* Quite lenient, e.g. allow empty as zero, but don't allow trailing
73696 * garbage.
73697 */
73698 s2n_flags = DUK_S2N_FLAG_TRIM_WHITE |
73699 DUK_S2N_FLAG_ALLOW_EXP |
73700 DUK_S2N_FLAG_ALLOW_PLUS |
73701 DUK_S2N_FLAG_ALLOW_MINUS |
73702 DUK_S2N_FLAG_ALLOW_INF |
73703 DUK_S2N_FLAG_ALLOW_FRAC |
73704 DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
73705 DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
73706 DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO |
73707 DUK_S2N_FLAG_ALLOW_LEADING_ZERO |
73708 DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT |
73709 DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT |
73710 DUK_S2N_FLAG_ALLOW_AUTO_BIN_INT;
73711
73712 duk_numconv_parse(ctx, 10 /*radix*/, s2n_flags);
73713
73714#if defined(DUK_USE_PREFER_SIZE)
73715 d = duk_get_number(ctx, -1);
73716 duk_pop(ctx);
73717#else
73718 thr->valstack_top--;
73719 DUK_ASSERT(DUK_TVAL_IS_NUMBER(thr->valstack_top));
73720 DUK_ASSERT(DUK_TVAL_IS_DOUBLE(thr->valstack_top)); /* no fastint conversion in numconv now */
73721 DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(thr->valstack_top));
73722 d = DUK_TVAL_GET_DOUBLE(thr->valstack_top); /* assumes not a fastint */
73723 DUK_TVAL_SET_UNDEFINED(thr->valstack_top);
73724#endif
73725
73726 return d;
73727}
73728
73729DUK_INTERNAL duk_double_t duk_js_tonumber(duk_hthread *thr, duk_tval *tv) {
73730 duk_context *ctx = (duk_hthread *) thr;
73731
73732 DUK_ASSERT(thr != NULL);
73733 DUK_ASSERT(tv != NULL);
73734
73735 switch (DUK_TVAL_GET_TAG(tv)) {
73736 case DUK_TAG_UNDEFINED: {
73737 /* return a specific NaN (although not strictly necessary) */
73739 DUK_DBLUNION_SET_NAN(&du);
73740 DUK_ASSERT(DUK_DBLUNION_IS_NORMALIZED(&du));
73741 return du.d;
73742 }
73743 case DUK_TAG_NULL: {
73744 /* +0.0 */
73745 return 0.0;
73746 }
73747 case DUK_TAG_BOOLEAN: {
73748 if (DUK_TVAL_IS_BOOLEAN_TRUE(tv)) {
73749 return 1.0;
73750 }
73751 return 0.0;
73752 }
73753 case DUK_TAG_STRING: {
73754 /* For Symbols ToNumber() is always a TypeError. */
73755 duk_hstring *h = DUK_TVAL_GET_STRING(tv);
73756 if (DUK_HSTRING_HAS_SYMBOL(h)) {
73757 DUK_ERROR_TYPE(thr, DUK_STR_CANNOT_NUMBER_COERCE_SYMBOL);
73758 }
73759 duk_push_hstring(ctx, h);
73760 return duk__tonumber_string_raw(thr);
73761 }
73762 case DUK_TAG_BUFFER: /* plain buffer treated like object */
73763 case DUK_TAG_OBJECT: {
73764 duk_double_t d;
73765 duk_push_tval(ctx, tv);
73766 duk_to_primitive(ctx, -1, DUK_HINT_NUMBER); /* 'tv' becomes invalid */
73767
73768 /* recursive call for a primitive value (guaranteed not to cause second
73769 * recursion).
73770 */
73771 DUK_ASSERT(duk_get_tval(ctx, -1) != NULL);
73772 d = duk_js_tonumber(thr, duk_get_tval(ctx, -1));
73773
73774 duk_pop(ctx);
73775 return d;
73776 }
73777 case DUK_TAG_POINTER: {
73778 /* Coerce like boolean */
73779 void *p = DUK_TVAL_GET_POINTER(tv);
73780 return (p != NULL ? 1.0 : 0.0);
73781 }
73782 case DUK_TAG_LIGHTFUNC: {
73783 /* +(function(){}) -> NaN */
73784 return DUK_DOUBLE_NAN;
73785 }
73786#if defined(DUK_USE_FASTINT)
73787 case DUK_TAG_FASTINT:
73788 return (duk_double_t) DUK_TVAL_GET_FASTINT(tv);
73789#endif
73790 default: {
73791 /* number */
73792 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv));
73793 DUK_ASSERT(DUK_TVAL_IS_DOUBLE(tv));
73794 return DUK_TVAL_GET_DOUBLE(tv);
73795 }
73796 }
73797
73798 DUK_UNREACHABLE();
73799}
73800
73801/*
73802 * ToInteger() (E5 Section 9.4)
73803 */
73804
73805/* exposed, used by e.g. duk_bi_date.c */
73806DUK_INTERNAL duk_double_t duk_js_tointeger_number(duk_double_t x) {
73807#if defined(DUK_USE_PREFER_SIZE)
73808 duk_small_int_t c = (duk_small_int_t) DUK_FPCLASSIFY(x);
73809
73810 if (DUK_UNLIKELY(c == DUK_FP_NAN)) {
73811 return 0.0;
73812 } else if (DUK_UNLIKELY(c == DUK_FP_INFINITE)) {
73813 return x;
73814 } else {
73815 /* Finite, including neg/pos zero. Neg zero sign must be
73816 * preserved.
73817 */
73818 return duk_double_trunc_towards_zero(x);
73819 }
73820#else /* DUK_USE_PREFER_SIZE */
73821 /* NaN and Infinity have the same exponent so it's a cheap
73822 * initial check for the rare path.
73823 */
73824 if (DUK_UNLIKELY(duk_double_is_nan_or_inf(x))) {
73825 if (duk_double_is_nan(x)) {
73826 return 0.0;
73827 } else {
73828 return x;
73829 }
73830 } else {
73831 return duk_double_trunc_towards_zero(x);
73832 }
73833#endif /* DUK_USE_PREFER_SIZE */
73834}
73835
73836DUK_INTERNAL duk_double_t duk_js_tointeger(duk_hthread *thr, duk_tval *tv) {
73837 /* XXX: fastint */
73838 duk_double_t d = duk_js_tonumber(thr, tv); /* invalidates tv */
73839 return duk_js_tointeger_number(d);
73840}
73841
73842/*
73843 * ToInt32(), ToUint32(), ToUint16() (E5 Sections 9.5, 9.6, 9.7)
73844 */
73845
73846/* combined algorithm matching E5 Sections 9.5 and 9.6 */
73847DUK_LOCAL duk_double_t duk__toint32_touint32_helper(duk_double_t x, duk_bool_t is_toint32) {
73848#if defined (DUK_USE_PREFER_SIZE)
73849 duk_small_int_t c;
73850#endif
73851
73852#if defined (DUK_USE_PREFER_SIZE)
73853 c = (duk_small_int_t) DUK_FPCLASSIFY(x);
73854 if (c == DUK_FP_NAN || c == DUK_FP_ZERO || c == DUK_FP_INFINITE) {
73855 return 0.0;
73856 }
73857#else
73858 if (duk_double_is_nan_zero_inf(x)) {
73859 return 0.0;
73860 }
73861#endif
73862
73863 /* x = sign(x) * floor(abs(x)), i.e. truncate towards zero, keep sign */
73864 x = duk_double_trunc_towards_zero(x);
73865
73866 /* NOTE: fmod(x) result sign is same as sign of x, which
73867 * differs from what Javascript wants (see Section 9.6).
73868 */
73869
73870 x = DUK_FMOD(x, DUK_DOUBLE_2TO32); /* -> x in ]-2**32, 2**32[ */
73871
73872 if (x < 0.0) {
73873 x += DUK_DOUBLE_2TO32;
73874 }
73875 DUK_ASSERT(x >= 0 && x < DUK_DOUBLE_2TO32); /* -> x in [0, 2**32[ */
73876
73877 if (is_toint32) {
73878 if (x >= DUK_DOUBLE_2TO31) {
73879 /* x in [2**31, 2**32[ */
73880
73881 x -= DUK_DOUBLE_2TO32; /* -> x in [-2**31,2**31[ */
73882 }
73883 }
73884
73885 return x;
73886}
73887
73888DUK_INTERNAL duk_int32_t duk_js_toint32(duk_hthread *thr, duk_tval *tv) {
73889 duk_double_t d;
73890
73891#if defined(DUK_USE_FASTINT)
73892 if (DUK_TVAL_IS_FASTINT(tv)) {
73893 return DUK_TVAL_GET_FASTINT_I32(tv);
73894 }
73895#endif
73896
73897 d = duk_js_tonumber(thr, tv); /* invalidates tv */
73898 d = duk__toint32_touint32_helper(d, 1);
73899 DUK_ASSERT(DUK_FPCLASSIFY(d) == DUK_FP_ZERO || DUK_FPCLASSIFY(d) == DUK_FP_NORMAL);
73900 DUK_ASSERT(d >= -2147483648.0 && d <= 2147483647.0); /* [-0x80000000,0x7fffffff] */
73901 DUK_ASSERT(d == ((duk_double_t) ((duk_int32_t) d))); /* whole, won't clip */
73902 return (duk_int32_t) d;
73903}
73904
73905
73906DUK_INTERNAL duk_uint32_t duk_js_touint32(duk_hthread *thr, duk_tval *tv) {
73907 duk_double_t d;
73908
73909#if defined(DUK_USE_FASTINT)
73910 if (DUK_TVAL_IS_FASTINT(tv)) {
73911 return DUK_TVAL_GET_FASTINT_U32(tv);
73912 }
73913#endif
73914
73915 d = duk_js_tonumber(thr, tv); /* invalidates tv */
73916 d = duk__toint32_touint32_helper(d, 0);
73917 DUK_ASSERT(DUK_FPCLASSIFY(d) == DUK_FP_ZERO || DUK_FPCLASSIFY(d) == DUK_FP_NORMAL);
73918 DUK_ASSERT(d >= 0.0 && d <= 4294967295.0); /* [0x00000000, 0xffffffff] */
73919 DUK_ASSERT(d == ((duk_double_t) ((duk_uint32_t) d))); /* whole, won't clip */
73920 return (duk_uint32_t) d;
73921
73922}
73923
73924DUK_INTERNAL duk_uint16_t duk_js_touint16(duk_hthread *thr, duk_tval *tv) {
73925 /* should be a safe way to compute this */
73926 return (duk_uint16_t) (duk_js_touint32(thr, tv) & 0x0000ffffU);
73927}
73928
73929/*
73930 * ToString() (E5 Section 9.8)
73931 * ToObject() (E5 Section 9.9)
73932 * CheckObjectCoercible() (E5 Section 9.10)
73933 * IsCallable() (E5 Section 9.11)
73934 *
73935 * ==> implemented in the API.
73936 */
73937
73938/*
73939 * Loose equality, strict equality, and SameValue (E5 Sections 11.9.1, 11.9.4,
73940 * 9.12). These have much in common so they can share some helpers.
73941 *
73942 * Future work notes:
73943 *
73944 * - Current implementation (and spec definition) has recursion; this should
73945 * be fixed if possible.
73946 *
73947 * - String-to-number coercion should be possible without going through the
73948 * value stack (and be more compact) if a shared helper is invoked.
73949 */
73950
73951/* Note that this is the same operation for strict and loose equality:
73952 * - E5 Section 11.9.3, step 1.c (loose)
73953 * - E5 Section 11.9.6, step 4 (strict)
73954 */
73955
73956DUK_LOCAL duk_bool_t duk__js_equals_number(duk_double_t x, duk_double_t y) {
73957#if defined(DUK_USE_PARANOID_MATH)
73958 /* Straightforward algorithm, makes fewer compiler assumptions. */
73959 duk_small_int_t cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
73960 duk_small_int_t cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
73961 if (cx == DUK_FP_NAN || cy == DUK_FP_NAN) {
73962 return 0;
73963 }
73964 if (cx == DUK_FP_ZERO && cy == DUK_FP_ZERO) {
73965 return 1;
73966 }
73967 if (x == y) {
73968 return 1;
73969 }
73970 return 0;
73971#else /* DUK_USE_PARANOID_MATH */
73972 /* Better equivalent algorithm. If the compiler is compliant, C and
73973 * Ecmascript semantics are identical for this particular comparison.
73974 * In particular, NaNs must never compare equal and zeroes must compare
73975 * equal regardless of sign. Could also use a macro, but this inlines
73976 * already nicely (no difference on gcc, for instance).
73977 */
73978 if (x == y) {
73979 /* IEEE requires that NaNs compare false */
73980 DUK_ASSERT(DUK_FPCLASSIFY(x) != DUK_FP_NAN);
73981 DUK_ASSERT(DUK_FPCLASSIFY(y) != DUK_FP_NAN);
73982 return 1;
73983 } else {
73984 /* IEEE requires that zeros compare the same regardless
73985 * of their signed, so if both x and y are zeroes, they
73986 * are caught above.
73987 */
73988 DUK_ASSERT(!(DUK_FPCLASSIFY(x) == DUK_FP_ZERO && DUK_FPCLASSIFY(y) == DUK_FP_ZERO));
73989 return 0;
73990 }
73991#endif /* DUK_USE_PARANOID_MATH */
73992}
73993
73994DUK_LOCAL duk_bool_t duk__js_samevalue_number(duk_double_t x, duk_double_t y) {
73995#if defined(DUK_USE_PARANOID_MATH)
73996 duk_small_int_t cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
73997 duk_small_int_t cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
73998
73999 if (cx == DUK_FP_NAN && cy == DUK_FP_NAN) {
74000 /* SameValue(NaN, NaN) = true, regardless of NaN sign or extra bits */
74001 return 1;
74002 }
74003 if (cx == DUK_FP_ZERO && cy == DUK_FP_ZERO) {
74004 /* Note: cannot assume that a non-zero return value of signbit() would
74005 * always be the same -- hence cannot (portably) use something like:
74006 *
74007 * signbit(x) == signbit(y)
74008 */
74009 duk_small_int_t sx = DUK_SIGNBIT(x) ? 1 : 0;
74010 duk_small_int_t sy = DUK_SIGNBIT(y) ? 1 : 0;
74011 return (sx == sy);
74012 }
74013
74014 /* normal comparison; known:
74015 * - both x and y are not NaNs (but one of them can be)
74016 * - both x and y are not zero (but one of them can be)
74017 * - x and y may be denormal or infinite
74018 */
74019
74020 return (x == y);
74021#else /* DUK_USE_PARANOID_MATH */
74022 duk_small_int_t cx = (duk_small_int_t) DUK_FPCLASSIFY(x);
74023 duk_small_int_t cy = (duk_small_int_t) DUK_FPCLASSIFY(y);
74024
74025 if (x == y) {
74026 /* IEEE requires that NaNs compare false */
74027 DUK_ASSERT(DUK_FPCLASSIFY(x) != DUK_FP_NAN);
74028 DUK_ASSERT(DUK_FPCLASSIFY(y) != DUK_FP_NAN);
74029
74030 /* Using classification has smaller footprint than direct comparison. */
74031 if (DUK_UNLIKELY(cx == DUK_FP_ZERO && cy == DUK_FP_ZERO)) {
74032 /* Note: cannot assume that a non-zero return value of signbit() would
74033 * always be the same -- hence cannot (portably) use something like:
74034 *
74035 * signbit(x) == signbit(y)
74036 */
74037 return duk_double_same_sign(x, y);
74038 }
74039 return 1;
74040 } else {
74041 /* IEEE requires that zeros compare the same regardless
74042 * of their sign, so if both x and y are zeroes, they
74043 * are caught above.
74044 */
74045 DUK_ASSERT(!(DUK_FPCLASSIFY(x) == DUK_FP_ZERO && DUK_FPCLASSIFY(y) == DUK_FP_ZERO));
74046
74047 /* Difference to non-strict/strict comparison is that NaNs compare
74048 * equal and signed zero signs matter.
74049 */
74050 if (DUK_UNLIKELY(cx == DUK_FP_NAN && cy == DUK_FP_NAN)) {
74051 /* SameValue(NaN, NaN) = true, regardless of NaN sign or extra bits */
74052 return 1;
74053 }
74054 return 0;
74055 }
74056#endif /* DUK_USE_PARANOID_MATH */
74057}
74058
74059DUK_INTERNAL duk_bool_t duk_js_equals_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags) {
74060 duk_context *ctx = (duk_context *) thr;
74061 duk_uint_t type_mask_x;
74062 duk_uint_t type_mask_y;
74063
74064 /* If flags != 0 (strict or SameValue), thr can be NULL. For loose
74065 * equals comparison it must be != NULL.
74066 */
74067 DUK_ASSERT(flags != 0 || thr != NULL);
74068
74069 /*
74070 * Same type?
74071 *
74072 * Note: since number values have no explicit tag in the 8-byte
74073 * representation, need the awkward if + switch.
74074 */
74075
74076#if defined(DUK_USE_FASTINT)
74077 if (DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y)) {
74078 if (DUK_TVAL_GET_FASTINT(tv_x) == DUK_TVAL_GET_FASTINT(tv_y)) {
74079 return 1;
74080 } else {
74081 return 0;
74082 }
74083 }
74084 else
74085#endif
74086 if (DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y)) {
74087 duk_double_t d1, d2;
74088
74089 /* Catches both doubles and cases where only one argument is
74090 * a fastint so can't assume a double.
74091 */
74092 d1 = DUK_TVAL_GET_NUMBER(tv_x);
74093 d2 = DUK_TVAL_GET_NUMBER(tv_y);
74094 if (DUK_UNLIKELY((flags & DUK_EQUALS_FLAG_SAMEVALUE) != 0)) {
74095 /* SameValue */
74096 return duk__js_samevalue_number(d1, d2);
74097 } else {
74098 /* equals and strict equals */
74099 return duk__js_equals_number(d1, d2);
74100 }
74101 } else if (DUK_TVAL_GET_TAG(tv_x) == DUK_TVAL_GET_TAG(tv_y)) {
74102 switch (DUK_TVAL_GET_TAG(tv_x)) {
74103 case DUK_TAG_UNDEFINED:
74104 case DUK_TAG_NULL: {
74105 return 1;
74106 }
74107 case DUK_TAG_BOOLEAN: {
74108 return DUK_TVAL_GET_BOOLEAN(tv_x) == DUK_TVAL_GET_BOOLEAN(tv_y);
74109 }
74110 case DUK_TAG_POINTER: {
74111 return DUK_TVAL_GET_POINTER(tv_x) == DUK_TVAL_GET_POINTER(tv_y);
74112 }
74113 case DUK_TAG_STRING:
74114 case DUK_TAG_OBJECT: {
74115 /* Heap pointer comparison suffices for strings and objects.
74116 * Symbols compare equal if they have the same internal
74117 * representation; again heap pointer comparison suffices.
74118 */
74119 return DUK_TVAL_GET_HEAPHDR(tv_x) == DUK_TVAL_GET_HEAPHDR(tv_y);
74120 }
74121 case DUK_TAG_BUFFER: {
74122 /* In Duktape 2.x plain buffers mimic Uint8Array objects
74123 * so always compare by heap pointer. In Duktape 1.x
74124 * strict comparison would compare heap pointers and
74125 * non-strict would compare contents.
74126 */
74127 return DUK_TVAL_GET_HEAPHDR(tv_x) == DUK_TVAL_GET_HEAPHDR(tv_y);
74128 }
74129 case DUK_TAG_LIGHTFUNC: {
74130 /* At least 'magic' has a significant impact on function
74131 * identity.
74132 */
74133 duk_small_uint_t lf_flags_x;
74134 duk_small_uint_t lf_flags_y;
74135 duk_c_function func_x;
74136 duk_c_function func_y;
74137
74138 DUK_TVAL_GET_LIGHTFUNC(tv_x, func_x, lf_flags_x);
74139 DUK_TVAL_GET_LIGHTFUNC(tv_y, func_y, lf_flags_y);
74140 return ((func_x == func_y) && (lf_flags_x == lf_flags_y)) ? 1 : 0;
74141 }
74142#if defined(DUK_USE_FASTINT)
74143 case DUK_TAG_FASTINT:
74144#endif
74145 default: {
74146 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_x));
74147 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_y));
74148 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_x));
74149 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_y));
74150 DUK_UNREACHABLE();
74151 return 0;
74152 }
74153 }
74154 }
74155
74156 if ((flags & (DUK_EQUALS_FLAG_STRICT | DUK_EQUALS_FLAG_SAMEVALUE)) != 0) {
74157 return 0;
74158 }
74159
74160 DUK_ASSERT(flags == 0); /* non-strict equality from here on */
74161
74162 /*
74163 * Types are different; various cases for non-strict comparison
74164 *
74165 * Since comparison is symmetric, we use a "swap trick" to reduce
74166 * code size.
74167 */
74168
74169 type_mask_x = duk_get_type_mask_tval(tv_x);
74170 type_mask_y = duk_get_type_mask_tval(tv_y);
74171
74172 /* Undefined/null are considered equal (e.g. "null == undefined" -> true). */
74173 if ((type_mask_x & (DUK_TYPE_MASK_UNDEFINED | DUK_TYPE_MASK_NULL)) &&
74174 (type_mask_y & (DUK_TYPE_MASK_NULL | DUK_TYPE_MASK_UNDEFINED))) {
74175 return 1;
74176 }
74177
74178 /* Number/string -> coerce string to number (e.g. "'1.5' == 1.5" -> true). */
74179 if ((type_mask_x & DUK_TYPE_MASK_NUMBER) && (type_mask_y & DUK_TYPE_MASK_STRING)) {
74180 if (!DUK_TVAL_STRING_IS_SYMBOL(tv_y)) {
74181 duk_double_t d1, d2;
74182 d1 = DUK_TVAL_GET_NUMBER(tv_x);
74183 d2 = duk_to_number_tval(ctx, tv_y);
74184 return duk__js_equals_number(d1, d2);
74185 }
74186 }
74187 if ((type_mask_x & DUK_TYPE_MASK_STRING) && (type_mask_y & DUK_TYPE_MASK_NUMBER)) {
74188 if (!DUK_TVAL_STRING_IS_SYMBOL(tv_x)) {
74189 duk_double_t d1, d2;
74190 d1 = DUK_TVAL_GET_NUMBER(tv_y);
74191 d2 = duk_to_number_tval(ctx, tv_x);
74192 return duk__js_equals_number(d1, d2);
74193 }
74194 }
74195
74196 /* Boolean/any -> coerce boolean to number and try again. If boolean is
74197 * compared to a pointer, the final comparison after coercion now always
74198 * yields false (as pointer vs. number compares to false), but this is
74199 * not special cased.
74200 *
74201 * ToNumber(bool) is +1.0 or 0.0. Tagged boolean value is always 0 or 1.
74202 */
74203 if (type_mask_x & DUK_TYPE_MASK_BOOLEAN) {
74204 DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv_x) == 0 || DUK_TVAL_GET_BOOLEAN(tv_x) == 1);
74205 duk_push_int(ctx, DUK_TVAL_GET_BOOLEAN(tv_x));
74206 duk_push_tval(ctx, tv_y);
74207 goto recursive_call;
74208 }
74209 if (type_mask_y & DUK_TYPE_MASK_BOOLEAN) {
74210 DUK_ASSERT(DUK_TVAL_GET_BOOLEAN(tv_y) == 0 || DUK_TVAL_GET_BOOLEAN(tv_y) == 1);
74211 duk_push_tval(ctx, tv_x);
74212 duk_push_int(ctx, DUK_TVAL_GET_BOOLEAN(tv_y));
74213 goto recursive_call;
74214 }
74215
74216 /* String-number-symbol/object -> coerce object to primitive (apparently without hint), then try again. */
74217 if ((type_mask_x & (DUK_TYPE_MASK_STRING | DUK_TYPE_MASK_NUMBER)) &&
74218 (type_mask_y & DUK_TYPE_MASK_OBJECT)) {
74219 /* No symbol check needed because symbols and strings are accepted. */
74220 duk_push_tval(ctx, tv_x);
74221 duk_push_tval(ctx, tv_y);
74222 duk_to_primitive(ctx, -1, DUK_HINT_NONE); /* apparently no hint? */
74223 goto recursive_call;
74224 }
74225 if ((type_mask_x & DUK_TYPE_MASK_OBJECT) &&
74226 (type_mask_y & (DUK_TYPE_MASK_STRING | DUK_TYPE_MASK_NUMBER))) {
74227 /* No symbol check needed because symbols and strings are accepted. */
74228 duk_push_tval(ctx, tv_x);
74229 duk_push_tval(ctx, tv_y);
74230 duk_to_primitive(ctx, -2, DUK_HINT_NONE); /* apparently no hint? */
74231 goto recursive_call;
74232 }
74233
74234 /* Nothing worked -> not equal. */
74235 return 0;
74236
74237 recursive_call:
74238 /* Shared code path to call the helper again with arguments on stack top. */
74239 {
74240 duk_bool_t rc;
74241 rc = duk_js_equals_helper(thr,
74242 DUK_GET_TVAL_NEGIDX(ctx, -2),
74243 DUK_GET_TVAL_NEGIDX(ctx, -1),
74244 0 /*flags:nonstrict*/);
74245 duk_pop_2(ctx);
74246 return rc;
74247 }
74248}
74249
74250/*
74251 * Comparisons (x >= y, x > y, x <= y, x < y)
74252 *
74253 * E5 Section 11.8.5: implement 'x < y' and then use negate and eval_left_first
74254 * flags to get the rest.
74255 */
74256
74257/* XXX: this should probably just operate on the stack top, because it
74258 * needs to push stuff on the stack anyway...
74259 */
74260
74261DUK_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) {
74262 duk_size_t prefix_len;
74263 duk_small_int_t rc;
74264
74265 prefix_len = (len1 <= len2 ? len1 : len2);
74266
74267 /* DUK_MEMCMP() is guaranteed to return zero (equal) for zero length
74268 * inputs so no zero length check is needed.
74269 */
74270 rc = DUK_MEMCMP((const void *) buf1,
74271 (const void *) buf2,
74272 (size_t) prefix_len);
74273
74274 if (rc < 0) {
74275 return -1;
74276 } else if (rc > 0) {
74277 return 1;
74278 }
74279
74280 /* prefix matches, lengths matter now */
74281 if (len1 < len2) {
74282 /* e.g. "x" < "xx" */
74283 return -1;
74284 } else if (len1 > len2) {
74285 return 1;
74286 }
74287
74288 return 0;
74289}
74290
74291DUK_INTERNAL duk_small_int_t duk_js_string_compare(duk_hstring *h1, duk_hstring *h2) {
74292 /*
74293 * String comparison (E5 Section 11.8.5, step 4), which
74294 * needs to compare codepoint by codepoint.
74295 *
74296 * However, UTF-8 allows us to use strcmp directly: the shared
74297 * prefix will be encoded identically (UTF-8 has unique encoding)
74298 * and the first differing character can be compared with a simple
74299 * unsigned byte comparison (which strcmp does).
74300 *
74301 * This will not work properly for non-xutf-8 strings, but this
74302 * is not an issue for compliance.
74303 */
74304
74305 DUK_ASSERT(h1 != NULL);
74306 DUK_ASSERT(h2 != NULL);
74307
74308 return duk_js_data_compare((const duk_uint8_t *) DUK_HSTRING_GET_DATA(h1),
74309 (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h2),
74310 (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1),
74311 (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2));
74312}
74313
74314#if 0 /* unused */
74315DUK_INTERNAL duk_small_int_t duk_js_buffer_compare(duk_heap *heap, duk_hbuffer *h1, duk_hbuffer *h2) {
74316 /* Similar to String comparison. */
74317
74318 DUK_ASSERT(h1 != NULL);
74319 DUK_ASSERT(h2 != NULL);
74320 DUK_UNREF(heap);
74321
74322 return duk_js_data_compare((const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(heap, h1),
74323 (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(heap, h2),
74324 (duk_size_t) DUK_HBUFFER_GET_SIZE(h1),
74325 (duk_size_t) DUK_HBUFFER_GET_SIZE(h2));
74326}
74327#endif
74328
74329#if defined(DUK_USE_FASTINT)
74330DUK_LOCAL duk_bool_t duk__compare_fastint(duk_bool_t retval, duk_int64_t v1, duk_int64_t v2) {
74331 DUK_ASSERT(retval == 0 || retval == 1);
74332 if (v1 < v2) {
74333 return retval ^ 1;
74334 } else {
74335 return retval;
74336 }
74337}
74338#endif
74339
74340#if defined(DUK_USE_PARANOID_MATH)
74341DUK_LOCAL duk_bool_t duk__compare_number(duk_bool_t retval, duk_double_t d1, duk_double_t d2) {
74342 duk_small_int_t c1, s1, c2, s2;
74343
74344 DUK_ASSERT(retval == 0 || retval == 1);
74345 c1 = (duk_small_int_t) DUK_FPCLASSIFY(d1);
74346 s1 = (duk_small_int_t) DUK_SIGNBIT(d1);
74347 c2 = (duk_small_int_t) DUK_FPCLASSIFY(d2);
74348 s2 = (duk_small_int_t) DUK_SIGNBIT(d2);
74349
74350 if (c1 == DUK_FP_NAN || c2 == DUK_FP_NAN) {
74351 return 0; /* Always false, regardless of negation. */
74352 }
74353
74354 if (c1 == DUK_FP_ZERO && c2 == DUK_FP_ZERO) {
74355 /* For all combinations: +0 < +0, +0 < -0, -0 < +0, -0 < -0,
74356 * steps e, f, and g.
74357 */
74358 return retval; /* false */
74359 }
74360
74361 if (d1 == d2) {
74362 return retval; /* false */
74363 }
74364
74365 if (c1 == DUK_FP_INFINITE && s1 == 0) {
74366 /* x == +Infinity */
74367 return retval; /* false */
74368 }
74369
74370 if (c2 == DUK_FP_INFINITE && s2 == 0) {
74371 /* y == +Infinity */
74372 return retval ^ 1; /* true */
74373 }
74374
74375 if (c2 == DUK_FP_INFINITE && s2 != 0) {
74376 /* y == -Infinity */
74377 return retval; /* false */
74378 }
74379
74380 if (c1 == DUK_FP_INFINITE && s1 != 0) {
74381 /* x == -Infinity */
74382 return retval ^ 1; /* true */
74383 }
74384
74385 if (d1 < d2) {
74386 return retval ^ 1; /* true */
74387 }
74388
74389 return retval; /* false */
74390}
74391#else /* DUK_USE_PARANOID_MATH */
74392DUK_LOCAL duk_bool_t duk__compare_number(duk_bool_t retval, duk_double_t d1, duk_double_t d2) {
74393 /* This comparison tree relies doesn't match the exact steps in
74394 * E5 Section 11.8.5 but should produce the same results. The
74395 * steps rely on exact IEEE semantics for NaNs, etc.
74396 */
74397
74398 DUK_ASSERT(retval == 0 || retval == 1);
74399 if (d1 < d2) {
74400 /* In no case should both (d1 < d2) and (d2 < d1) be true.
74401 * It's possible that neither is true though, and that's
74402 * handled below.
74403 */
74404 DUK_ASSERT(!(d2 < d1));
74405
74406 /* - d1 < d2, both d1/d2 are normals (not Infinity, not NaN)
74407 * - d2 is +Infinity, d1 != +Infinity and NaN
74408 * - d1 is -Infinity, d2 != -Infinity and NaN
74409 */
74410 return retval ^ 1;
74411 } else {
74412 if (d2 < d1) {
74413 /* - !(d1 < d2), both d1/d2 are normals (not Infinity, not NaN)
74414 * - d1 is +Infinity, d2 != +Infinity and NaN
74415 * - d2 is -Infinity, d1 != -Infinity and NaN
74416 */
74417 return retval;
74418 } else {
74419 /* - d1 and/or d2 is NaN
74420 * - d1 and d2 are both +/- 0
74421 * - d1 == d2 (including infinities)
74422 */
74423 if (duk_double_is_nan(d1) || duk_double_is_nan(d2)) {
74424 /* Note: undefined from Section 11.8.5 always
74425 * results in false return (see e.g. Section
74426 * 11.8.3) - hence special treatment here.
74427 */
74428 return 0; /* zero regardless of negation */
74429 } else {
74430 return retval;
74431 }
74432 }
74433 }
74434}
74435#endif /* DUK_USE_PARANOID_MATH */
74436
74437DUK_INTERNAL duk_bool_t duk_js_compare_helper(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y, duk_small_int_t flags) {
74438 duk_context *ctx = (duk_context *) thr;
74439 duk_double_t d1, d2;
74440 duk_small_int_t rc;
74441 duk_bool_t retval;
74442
74443 DUK_ASSERT(DUK_COMPARE_FLAG_NEGATE == 1); /* Rely on this flag being lowest. */
74444 retval = flags & DUK_COMPARE_FLAG_NEGATE;
74445 DUK_ASSERT(retval == 0 || retval == 1);
74446
74447 /* Fast path for fastints */
74448#if defined(DUK_USE_FASTINT)
74449 if (DUK_LIKELY(DUK_TVAL_IS_FASTINT(tv_x) && DUK_TVAL_IS_FASTINT(tv_y))) {
74450 return duk__compare_fastint(retval,
74451 DUK_TVAL_GET_FASTINT(tv_x),
74452 DUK_TVAL_GET_FASTINT(tv_y));
74453 }
74454#endif /* DUK_USE_FASTINT */
74455
74456 /* Fast path for numbers (one of which may be a fastint) */
74457#if !defined(DUK_USE_PREFER_SIZE)
74458 if (DUK_LIKELY(DUK_TVAL_IS_NUMBER(tv_x) && DUK_TVAL_IS_NUMBER(tv_y))) {
74459 return duk__compare_number(retval,
74460 DUK_TVAL_GET_NUMBER(tv_x),
74461 DUK_TVAL_GET_NUMBER(tv_y));
74462 }
74463#endif
74464
74465 /* Slow path */
74466
74467 duk_push_tval(ctx, tv_x);
74468 duk_push_tval(ctx, tv_y);
74469
74470 if (flags & DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) {
74471 duk_to_primitive(ctx, -2, DUK_HINT_NUMBER);
74472 duk_to_primitive(ctx, -1, DUK_HINT_NUMBER);
74473 } else {
74474 duk_to_primitive(ctx, -1, DUK_HINT_NUMBER);
74475 duk_to_primitive(ctx, -2, DUK_HINT_NUMBER);
74476 }
74477
74478 /* Note: reuse variables */
74479 tv_x = DUK_GET_TVAL_NEGIDX(ctx, -2);
74480 tv_y = DUK_GET_TVAL_NEGIDX(ctx, -1);
74481
74482 if (DUK_TVAL_IS_STRING(tv_x) && DUK_TVAL_IS_STRING(tv_y)) {
74483 duk_hstring *h1 = DUK_TVAL_GET_STRING(tv_x);
74484 duk_hstring *h2 = DUK_TVAL_GET_STRING(tv_y);
74485 DUK_ASSERT(h1 != NULL);
74486 DUK_ASSERT(h2 != NULL);
74487
74488 if (!DUK_HSTRING_HAS_SYMBOL(h1) && !DUK_HSTRING_HAS_SYMBOL(h2)) {
74489 rc = duk_js_string_compare(h1, h2);
74490 duk_pop_2(ctx);
74491 if (rc < 0) {
74492 return retval ^ 1;
74493 } else {
74494 return retval;
74495 }
74496 }
74497
74498 /* One or both are Symbols: fall through to handle in the
74499 * generic path. Concretely, ToNumber() will fail.
74500 */
74501 }
74502
74503 /* Ordering should not matter (E5 Section 11.8.5, step 3.a). */
74504#if 0
74505 if (flags & DUK_COMPARE_FLAG_EVAL_LEFT_FIRST) {
74506 d1 = duk_to_number_m2(ctx);
74507 d2 = duk_to_number_m1(ctx);
74508 } else {
74509 d2 = duk_to_number_m1(ctx);
74510 d1 = duk_to_number_m2(ctx);
74511 }
74512#endif
74513 d1 = duk_to_number_m2(ctx);
74514 d2 = duk_to_number_m1(ctx);
74515
74516 /* We want to duk_pop_2(ctx); because the values are numbers
74517 * no decref check is needed.
74518 */
74519#if defined(DUK_USE_PREFER_SIZE)
74520 duk_pop_2(ctx);
74521#else
74522 DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk_get_tval(ctx, -2)));
74523 DUK_ASSERT(!DUK_TVAL_NEEDS_REFCOUNT_UPDATE(duk_get_tval(ctx, -1)));
74524 DUK_ASSERT(duk_get_top(ctx) >= 2);
74525 ((duk_hthread *) ctx)->valstack_top -= 2;
74526 tv_x = ((duk_hthread *) ctx)->valstack_top;
74527 tv_y = tv_x + 1;
74528 DUK_TVAL_SET_UNDEFINED(tv_x); /* Value stack policy */
74529 DUK_TVAL_SET_UNDEFINED(tv_y);
74530#endif
74531
74532 return duk__compare_number(retval, d1, d2);
74533}
74534
74535/*
74536 * instanceof
74537 */
74538
74539/*
74540 * E5 Section 11.8.6 describes the main algorithm, which uses
74541 * [[HasInstance]]. [[HasInstance]] is defined for only
74542 * function objects:
74543 *
74544 * - Normal functions:
74545 * E5 Section 15.3.5.3
74546 * - Functions established with Function.prototype.bind():
74547 * E5 Section 15.3.4.5.3
74548 *
74549 * For other objects, a TypeError is thrown.
74550 *
74551 * Limited Proxy support: don't support 'getPrototypeOf' trap but
74552 * continue lookup in Proxy target if the value is a Proxy.
74553 */
74554
74555DUK_INTERNAL duk_bool_t duk_js_instanceof(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
74556 duk_context *ctx = (duk_context *) thr;
74557 duk_hobject *func;
74558 duk_hobject *val;
74559 duk_hobject *proto;
74560 duk_tval *tv;
74561 duk_uint_t sanity;
74562 duk_bool_t skip_first;
74563
74564 /*
74565 * Get the values onto the stack first. It would be possible to cover
74566 * some normal cases without resorting to the value stack.
74567 *
74568 * The right hand side could be a light function (as they generally
74569 * behave like objects). Light functions never have a 'prototype'
74570 * property so E5.1 Section 15.3.5.3 step 3 always throws a TypeError.
74571 * Using duk_require_hobject() is thus correct (except for error msg).
74572 */
74573
74574 duk_push_tval(ctx, tv_x);
74575 duk_push_tval(ctx, tv_y);
74576 func = duk_require_hobject(ctx, -1);
74577
74578 /*
74579 * For bound objects, [[HasInstance]] just calls the target function
74580 * [[HasInstance]]. If that is again a bound object, repeat until
74581 * we find a non-bound Function object.
74582 */
74583
74584 /* XXX: this bound function resolution also happens elsewhere,
74585 * move into a shared helper.
74586 */
74587
74588 sanity = DUK_HOBJECT_BOUND_CHAIN_SANITY;
74589 do {
74590 /* check func supports [[HasInstance]] (this is checked for every function
74591 * in the bound chain, including the final one)
74592 */
74593
74594 if (!DUK_HOBJECT_IS_CALLABLE(func)) {
74595 /*
74596 * Note: of native Ecmascript objects, only Function instances
74597 * have a [[HasInstance]] internal property. Custom objects might
74598 * also have it, but not in current implementation.
74599 *
74600 * XXX: add a separate flag, DUK_HOBJECT_FLAG_ALLOW_INSTANCEOF?
74601 */
74602 DUK_ERROR_TYPE(thr, "invalid instanceof rval");
74603 }
74604
74605 if (!DUK_HOBJECT_HAS_BOUNDFUNC(func)) {
74606 break;
74607 }
74608
74609 /* [ ... lval rval ] */
74610
74611 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_TARGET); /* -> [ ... lval rval new_rval ] */
74612 duk_replace(ctx, -1); /* -> [ ... lval new_rval ] */
74613 func = duk_require_hobject(ctx, -1);
74614
74615 /* func support for [[HasInstance]] checked in the beginning of the loop */
74616 } while (--sanity > 0);
74617
74618 if (sanity == 0) {
74619 DUK_ERROR_RANGE(thr, DUK_STR_BOUND_CHAIN_LIMIT);
74620 }
74621
74622 /*
74623 * 'func' is now a non-bound object which supports [[HasInstance]]
74624 * (which here just means DUK_HOBJECT_FLAG_CALLABLE). Move on
74625 * to execute E5 Section 15.3.5.3.
74626 */
74627
74628 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func));
74629 DUK_ASSERT(DUK_HOBJECT_IS_CALLABLE(func));
74630
74631 /* [ ... lval rval(func) ] */
74632
74633 /* For lightfuncs, buffers, and pointers start the comparison directly
74634 * from the virtual prototype object.
74635 */
74636 skip_first = 0;
74637 tv = DUK_GET_TVAL_NEGIDX(ctx, -2);
74638 switch (DUK_TVAL_GET_TAG(tv)) {
74639 case DUK_TAG_LIGHTFUNC:
74640 val = thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE];
74641 DUK_ASSERT(val != NULL);
74642 break;
74643 case DUK_TAG_BUFFER:
74644 val = thr->builtins[DUK_BIDX_UINT8ARRAY_PROTOTYPE];
74645 DUK_ASSERT(val != NULL);
74646 break;
74647 case DUK_TAG_POINTER:
74648 val = thr->builtins[DUK_BIDX_POINTER_PROTOTYPE];
74649 DUK_ASSERT(val != NULL);
74650 break;
74651 case DUK_TAG_OBJECT:
74652 skip_first = 1; /* Ignore object itself on first round. */
74653 val = DUK_TVAL_GET_OBJECT(tv);
74654 DUK_ASSERT(val != NULL);
74655 break;
74656 default:
74657 goto pop_and_false;
74658 }
74659 DUK_ASSERT(val != NULL); /* Loop doesn't actually rely on this. */
74660
74661 duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_PROTOTYPE); /* -> [ ... lval rval rval.prototype ] */
74662 proto = duk_require_hobject(ctx, -1);
74663 duk_pop(ctx); /* -> [ ... lval rval ] */
74664
74665 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
74666 do {
74667 /*
74668 * Note: prototype chain is followed BEFORE first comparison. This
74669 * means that the instanceof lval is never itself compared to the
74670 * rval.prototype property. This is apparently intentional, see E5
74671 * Section 15.3.5.3, step 4.a.
74672 *
74673 * Also note:
74674 *
74675 * js> (function() {}) instanceof Function
74676 * true
74677 * js> Function instanceof Function
74678 * true
74679 *
74680 * For the latter, h_proto will be Function.prototype, which is the
74681 * built-in Function prototype. Because Function.[[Prototype]] is
74682 * also the built-in Function prototype, the result is true.
74683 */
74684
74685 if (!val) {
74686 goto pop_and_false;
74687 }
74688
74689 DUK_ASSERT(val != NULL);
74690#if defined(DUK_USE_ES6_PROXY)
74691 val = duk_hobject_resolve_proxy_target(thr, val);
74692#endif
74693
74694 if (skip_first) {
74695 skip_first = 0;
74696 } else if (val == proto) {
74697 goto pop_and_true;
74698 }
74699
74700 DUK_ASSERT(val != NULL);
74701 val = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, val);
74702 } while (--sanity > 0);
74703
74704 if (sanity == 0) {
74705 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
74706 }
74707 DUK_UNREACHABLE();
74708
74709 pop_and_false:
74710 duk_pop_2(ctx);
74711 return 0;
74712
74713 pop_and_true:
74714 duk_pop_2(ctx);
74715 return 1;
74716}
74717
74718/*
74719 * in
74720 */
74721
74722/*
74723 * E5 Sections 11.8.7, 8.12.6.
74724 *
74725 * Basically just a property existence check using [[HasProperty]].
74726 */
74727
74728DUK_INTERNAL duk_bool_t duk_js_in(duk_hthread *thr, duk_tval *tv_x, duk_tval *tv_y) {
74729 duk_context *ctx = (duk_context *) thr;
74730 duk_bool_t retval;
74731
74732 /*
74733 * Get the values onto the stack first. It would be possible to cover
74734 * some normal cases without resorting to the value stack (e.g. if
74735 * lval is already a string).
74736 */
74737
74738 /* XXX: The ES5/5.1/6 specifications require that the key in 'key in obj'
74739 * must be string coerced before the internal HasProperty() algorithm is
74740 * invoked. A fast path skipping coercion could be safely implemented for
74741 * numbers (as number-to-string coercion has no side effects). For ES2015
74742 * proxy behavior, the trap 'key' argument must be in a string coerced
74743 * form (which is a shame).
74744 */
74745
74746 /* TypeError if rval is not an object or object like (e.g. lightfunc
74747 * or plain buffer).
74748 */
74749 duk_push_tval(ctx, tv_x);
74750 duk_push_tval(ctx, tv_y);
74751 duk_require_type_mask(ctx, -1, DUK_TYPE_MASK_OBJECT | DUK_TYPE_MASK_LIGHTFUNC | DUK_TYPE_MASK_BUFFER);
74752
74753 (void) duk_to_property_key_hstring(ctx, -2);
74754
74755 retval = duk_hobject_hasprop(thr,
74756 DUK_GET_TVAL_NEGIDX(ctx, -1),
74757 DUK_GET_TVAL_NEGIDX(ctx, -2));
74758
74759 duk_pop_2(ctx);
74760 return retval;
74761}
74762
74763/*
74764 * typeof
74765 *
74766 * E5 Section 11.4.3.
74767 *
74768 * Very straightforward. The only question is what to return for our
74769 * non-standard tag / object types.
74770 *
74771 * There is an unfortunate string constant define naming problem with
74772 * typeof return values for e.g. "Object" and "object"; careful with
74773 * the built-in string defines. The LC_XXX defines are used for the
74774 * lowercase variants now.
74775 */
74776
74777DUK_INTERNAL duk_small_uint_t duk_js_typeof_stridx(duk_tval *tv_x) {
74778 duk_small_uint_t stridx = 0;
74779
74780 switch (DUK_TVAL_GET_TAG(tv_x)) {
74781 case DUK_TAG_UNDEFINED: {
74782 stridx = DUK_STRIDX_LC_UNDEFINED;
74783 break;
74784 }
74785 case DUK_TAG_NULL: {
74786 /* Note: not a typo, "object" is returned for a null value. */
74787 stridx = DUK_STRIDX_LC_OBJECT;
74788 break;
74789 }
74790 case DUK_TAG_BOOLEAN: {
74791 stridx = DUK_STRIDX_LC_BOOLEAN;
74792 break;
74793 }
74794 case DUK_TAG_POINTER: {
74795 /* Implementation specific. */
74796 stridx = DUK_STRIDX_LC_POINTER;
74797 break;
74798 }
74799 case DUK_TAG_STRING: {
74800 duk_hstring *str;
74801
74802 /* All internal keys are identified as Symbols. */
74803 str = DUK_TVAL_GET_STRING(tv_x);
74804 DUK_ASSERT(str != NULL);
74805 if (DUK_HSTRING_HAS_SYMBOL(str)) {
74806 stridx = DUK_STRIDX_LC_SYMBOL;
74807 } else {
74808 stridx = DUK_STRIDX_LC_STRING;
74809 }
74810 break;
74811 }
74812 case DUK_TAG_OBJECT: {
74813 duk_hobject *obj = DUK_TVAL_GET_OBJECT(tv_x);
74814 DUK_ASSERT(obj != NULL);
74815 if (DUK_HOBJECT_IS_CALLABLE(obj)) {
74816 stridx = DUK_STRIDX_LC_FUNCTION;
74817 } else {
74818 stridx = DUK_STRIDX_LC_OBJECT;
74819 }
74820 break;
74821 }
74822 case DUK_TAG_BUFFER: {
74823 /* Implementation specific. In Duktape 1.x this would be
74824 * 'buffer', in Duktape 2.x changed to 'object' because plain
74825 * buffers now mimic Uint8Array objects.
74826 */
74827 stridx = DUK_STRIDX_LC_OBJECT;
74828 break;
74829 }
74830 case DUK_TAG_LIGHTFUNC: {
74831 stridx = DUK_STRIDX_LC_FUNCTION;
74832 break;
74833 }
74834#if defined(DUK_USE_FASTINT)
74835 case DUK_TAG_FASTINT:
74836#endif
74837 default: {
74838 /* number */
74839 DUK_ASSERT(!DUK_TVAL_IS_UNUSED(tv_x));
74840 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv_x));
74841 stridx = DUK_STRIDX_LC_NUMBER;
74842 break;
74843 }
74844 }
74845
74846 DUK_ASSERT_STRIDX_VALID(stridx);
74847 return stridx;
74848}
74849
74850/*
74851 * Array index and length
74852 *
74853 * Array index: E5 Section 15.4
74854 * Array length: E5 Section 15.4.5.1 steps 3.c - 3.d (array length write)
74855 *
74856 * duk_js_to_arrayindex_string_helper() computes the array index from
74857 * string contents alone. Depending on options it's only called during
74858 * string intern (and value stored to duk_hstring) or it's called also
74859 * at runtime.
74860 */
74861
74862DUK_INTERNAL duk_small_int_t duk_js_to_arrayindex_raw_string(const duk_uint8_t *str, duk_uint32_t blen, duk_uarridx_t *out_idx) {
74863 duk_uarridx_t res, new_res;
74864
74865 if (blen == 0 || blen > 10) {
74866 goto parse_fail;
74867 }
74868 if (str[0] == (duk_uint8_t) '0' && blen > 1) {
74869 goto parse_fail;
74870 }
74871
74872 /* Accept 32-bit decimal integers, no leading zeroes, signs, etc.
74873 * Leading zeroes are not accepted (zero index "0" is an exception
74874 * handled above).
74875 */
74876
74877 res = 0;
74878 while (blen-- > 0) {
74879 duk_uint8_t c = *str++;
74880 if (c >= (duk_uint8_t) '0' && c <= (duk_uint8_t) '9') {
74881 new_res = res * 10 + (duk_uint32_t) (c - (duk_uint8_t) '0');
74882 if (new_res < res) {
74883 /* overflow, more than 32 bits -> not an array index */
74884 goto parse_fail;
74885 }
74886 res = new_res;
74887 } else {
74888 goto parse_fail;
74889 }
74890 }
74891
74892 *out_idx = res;
74893 return 1;
74894
74895 parse_fail:
74896 *out_idx = DUK_HSTRING_NO_ARRAY_INDEX;
74897 return 0;
74898}
74899
74900/* Called by duk_hstring.h macros */
74901DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_string_helper(duk_hstring *h) {
74902 duk_uarridx_t res;
74903 duk_small_int_t rc;
74904
74905 if (!DUK_HSTRING_HAS_ARRIDX(h)) {
74906 return DUK_HSTRING_NO_ARRAY_INDEX;
74907 }
74908
74909 rc = duk_js_to_arrayindex_raw_string(DUK_HSTRING_GET_DATA(h),
74910 DUK_HSTRING_GET_BYTELEN(h),
74911 &res);
74912 DUK_UNREF(rc);
74913 DUK_ASSERT(rc != 0);
74914 return res;
74915}
74916/*
74917 * Identifier access and function closure handling.
74918 *
74919 * Provides the primitives for slow path identifier accesses: GETVAR,
74920 * PUTVAR, DELVAR, etc. The fast path, direct register accesses, should
74921 * be used for most identifier accesses. Consequently, these slow path
74922 * primitives should be optimized for maximum compactness.
74923 *
74924 * Ecmascript environment records (declarative and object) are represented
74925 * as internal objects with control keys. Environment records have a
74926 * parent record ("outer environment reference") which is represented by
74927 * the implicit prototype for technical reasons (in other words, it is a
74928 * convenient field). The prototype chain is not followed in the ordinary
74929 * sense for variable lookups.
74930 *
74931 * See identifier-handling.rst for more details on the identifier algorithms
74932 * and the internal representation. See function-objects.rst for details on
74933 * what function templates and instances are expected to look like.
74934 *
74935 * Care must be taken to avoid duk_tval pointer invalidation caused by
74936 * e.g. value stack or object resizing.
74937 *
74938 * TODO: properties for function instances could be initialized much more
74939 * efficiently by creating a property allocation for a certain size and
74940 * filling in keys and values directly (and INCREFing both with "bulk incref"
74941 * primitives.
74942 *
74943 * XXX: duk_hobject_getprop() and duk_hobject_putprop() calls are a bit
74944 * awkward (especially because they follow the prototype chain); rework
74945 * if "raw" own property helpers are added.
74946 */
74947
74948/* #include duk_internal.h -> already included */
74949
74950/*
74951 * Local result type for duk__get_identifier_reference() lookup.
74952 */
74953
74954typedef struct {
74955 duk_hobject *holder; /* for object-bound identifiers */
74956 duk_tval *value; /* for register-bound and declarative env identifiers */
74957 duk_int_t attrs; /* property attributes for identifier (relevant if value != NULL) */
74958 duk_tval *this_binding;
74959 duk_hobject *env;
74961
74962/*
74963 * Create a new function object based on a "template function" which contains
74964 * compiled bytecode, constants, etc, but lacks a lexical environment.
74965 *
74966 * Ecmascript requires that each created closure is a separate object, with
74967 * its own set of editable properties. However, structured property values
74968 * (such as the formal arguments list and the variable map) are shared.
74969 * Also the bytecode, constants, and inner functions are shared.
74970 *
74971 * See E5 Section 13.2 for detailed requirements on the function objects;
74972 * there are no similar requirements for function "templates" which are an
74973 * implementation dependent internal feature. Also see function-objects.rst
74974 * for a discussion on the function instance properties provided by this
74975 * implementation.
74976 *
74977 * Notes:
74978 *
74979 * * Order of internal properties should match frequency of use, since the
74980 * properties will be linearly scanned on lookup (functions usually don't
74981 * have enough properties to warrant a hash part).
74982 *
74983 * * The created closure is independent of its template; they do share the
74984 * same 'data' buffer object, but the template object itself can be freed
74985 * even if the closure object remains reachable.
74986 */
74987
74988DUK_LOCAL void duk__inc_data_inner_refcounts(duk_hthread *thr, duk_hcompfunc *f) {
74989 duk_tval *tv, *tv_end;
74990 duk_hobject **funcs, **funcs_end;
74991
74992 DUK_UNREF(thr);
74993
74994 /* If function creation fails due to out-of-memory, the data buffer
74995 * pointer may be NULL in some cases. That's actually possible for
74996 * GC code, but shouldn't be possible here because the incomplete
74997 * function will be unwound from the value stack and never instantiated.
74998 */
74999 DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, f) != NULL);
75000
75001 tv = DUK_HCOMPFUNC_GET_CONSTS_BASE(thr->heap, f);
75002 tv_end = DUK_HCOMPFUNC_GET_CONSTS_END(thr->heap, f);
75003 while (tv < tv_end) {
75004 DUK_TVAL_INCREF(thr, tv);
75005 tv++;
75006 }
75007
75008 funcs = DUK_HCOMPFUNC_GET_FUNCS_BASE(thr->heap, f);
75009 funcs_end = DUK_HCOMPFUNC_GET_FUNCS_END(thr->heap, f);
75010 while (funcs < funcs_end) {
75011 DUK_HEAPHDR_INCREF(thr, (duk_heaphdr *) *funcs);
75012 funcs++;
75013 }
75014}
75015
75016/* Push a new closure on the stack.
75017 *
75018 * Note: if fun_temp has NEWENV, i.e. a new lexical and variable declaration
75019 * is created when the function is called, only outer_lex_env matters
75020 * (outer_var_env is ignored and may or may not be same as outer_lex_env).
75021 */
75022
75023DUK_LOCAL const duk_uint16_t duk__closure_copy_proplist[] = {
75024 /* order: most frequent to least frequent */
75025 DUK_STRIDX_INT_VARMAP,
75026 DUK_STRIDX_INT_FORMALS,
75027#if defined(DUK_USE_PC2LINE)
75028 DUK_STRIDX_INT_PC2LINE,
75029#endif
75030#if defined(DUK_USE_FUNC_FILENAME_PROPERTY)
75031 DUK_STRIDX_FILE_NAME,
75032#endif
75033#if defined(DUK_USE_NONSTD_FUNC_SOURCE_PROPERTY)
75034 DUK_STRIDX_INT_SOURCE
75035#endif
75036};
75037
75038DUK_INTERNAL
75039void duk_js_push_closure(duk_hthread *thr,
75040 duk_hcompfunc *fun_temp,
75041 duk_hobject *outer_var_env,
75042 duk_hobject *outer_lex_env,
75043 duk_bool_t add_auto_proto) {
75044 duk_context *ctx = (duk_context *) thr;
75045 duk_hcompfunc *fun_clos;
75046 duk_small_uint_t i;
75047 duk_uint_t len_value;
75048
75049 DUK_ASSERT(fun_temp != NULL);
75050 DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_temp) != NULL);
75051 DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, fun_temp) != NULL);
75052 DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, fun_temp) != NULL);
75053 DUK_ASSERT(outer_var_env != NULL);
75054 DUK_ASSERT(outer_lex_env != NULL);
75055 DUK_UNREF(len_value);
75056
75057 fun_clos = duk_push_hcompfunc(ctx);
75058 DUK_ASSERT(fun_clos != NULL);
75059 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, (duk_hobject *) fun_clos) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
75060
75061 duk_push_hobject(ctx, &fun_temp->obj); /* -> [ ... closure template ] */
75062
75063 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC((duk_hobject *) fun_clos));
75064 DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_clos) == NULL);
75065 DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, fun_clos) == NULL);
75066 DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, fun_clos) == NULL);
75067
75068 DUK_HCOMPFUNC_SET_DATA(thr->heap, fun_clos, DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_temp));
75069 DUK_HCOMPFUNC_SET_FUNCS(thr->heap, fun_clos, DUK_HCOMPFUNC_GET_FUNCS(thr->heap, fun_temp));
75070 DUK_HCOMPFUNC_SET_BYTECODE(thr->heap, fun_clos, DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, fun_temp));
75071
75072 /* Note: all references inside 'data' need to get their refcounts
75073 * upped too. This is the case because refcounts are decreased
75074 * through every function referencing 'data' independently.
75075 */
75076
75077 DUK_HBUFFER_INCREF(thr, DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_clos));
75078 duk__inc_data_inner_refcounts(thr, fun_temp);
75079
75080 fun_clos->nregs = fun_temp->nregs;
75081 fun_clos->nargs = fun_temp->nargs;
75082#if defined(DUK_USE_DEBUGGER_SUPPORT)
75083 fun_clos->start_line = fun_temp->start_line;
75084 fun_clos->end_line = fun_temp->end_line;
75085#endif
75086
75087 DUK_ASSERT(DUK_HCOMPFUNC_GET_DATA(thr->heap, fun_clos) != NULL);
75088 DUK_ASSERT(DUK_HCOMPFUNC_GET_FUNCS(thr->heap, fun_clos) != NULL);
75089 DUK_ASSERT(DUK_HCOMPFUNC_GET_BYTECODE(thr->heap, fun_clos) != NULL);
75090
75091 /* XXX: could also copy from template, but there's no way to have any
75092 * other value here now (used code has no access to the template).
75093 */
75094 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, &fun_clos->obj, thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
75095
75096 /* Copy duk_hobject flags as is from the template using a mask.
75097 * Leave out duk_heaphdr owned flags just in case (e.g. if there's
75098 * some GC flag or similar). Some flags can then be adjusted
75099 * separately if necessary.
75100 */
75101
75102 /* DUK_HEAPHDR_SET_FLAGS() masks changes to non-duk_heaphdr flags only. */
75103 DUK_HEAPHDR_SET_FLAGS((duk_heaphdr *) fun_clos, DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) fun_temp));
75104 DUK_DD(DUK_DDPRINT("fun_temp heaphdr flags: 0x%08lx, fun_clos heaphdr flags: 0x%08lx",
75105 (unsigned long) DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) fun_temp),
75106 (unsigned long) DUK_HEAPHDR_GET_FLAGS_RAW((duk_heaphdr *) fun_clos)));
75107
75108 DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(&fun_clos->obj));
75109 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(&fun_clos->obj));
75110 DUK_ASSERT(DUK_HOBJECT_HAS_COMPFUNC(&fun_clos->obj));
75111 DUK_ASSERT(!DUK_HOBJECT_HAS_NATFUNC(&fun_clos->obj));
75112 DUK_ASSERT(!DUK_HOBJECT_HAS_THREAD(&fun_clos->obj));
75113 /* DUK_HOBJECT_FLAG_ARRAY_PART: don't care */
75114 /* DUK_HOBJECT_FLAG_NEWENV: handled below */
75115 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(&fun_clos->obj));
75116 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_STRINGOBJ(&fun_clos->obj));
75117 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARGUMENTS(&fun_clos->obj));
75118
75119 if (!DUK_HOBJECT_HAS_CONSTRUCTABLE(&fun_clos->obj)) {
75120 /* If the template is not constructable don't add an automatic
75121 * .prototype property. This is the case for e.g. ES2015 object
75122 * literal getters/setters and method definitions.
75123 */
75124 add_auto_proto = 0;
75125 }
75126
75127 /*
75128 * Setup environment record properties based on the template and
75129 * its flags.
75130 *
75131 * If DUK_HOBJECT_HAS_NEWENV(fun_temp) is true, the environment
75132 * records represent identifiers "outside" the function; the
75133 * "inner" environment records are created on demand. Otherwise,
75134 * the environment records are those that will be directly used
75135 * (e.g. for declarations).
75136 *
75137 * _Lexenv is always set; _Varenv defaults to _Lexenv if missing,
75138 * so _Varenv is only set if _Lexenv != _Varenv.
75139 *
75140 * This is relatively complex, see doc/identifier-handling.rst.
75141 */
75142
75143 if (DUK_HOBJECT_HAS_NEWENV(&fun_clos->obj)) {
75144#if defined(DUK_USE_FUNC_NAME_PROPERTY)
75145 if (DUK_HOBJECT_HAS_NAMEBINDING(&fun_clos->obj)) {
75146 duk_hobject *proto;
75147 duk_hobject *new_env;
75148
75149 /*
75150 * Named function expression, name needs to be bound
75151 * in an intermediate environment record. The "outer"
75152 * lexical/variable environment will thus be:
75153 *
75154 * a) { funcname: <func>, __prototype: outer_lex_env }
75155 * b) { funcname: <func>, __prototype: <globalenv> } (if outer_lex_env missing)
75156 */
75157
75158 if (outer_lex_env) {
75159 proto = outer_lex_env;
75160 } else {
75161 proto = thr->builtins[DUK_BIDX_GLOBAL_ENV];
75162 }
75163
75164 /* -> [ ... closure template env ] */
75165 new_env = duk_push_object_helper_proto(ctx,
75166 DUK_HOBJECT_FLAG_EXTENSIBLE |
75167 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
75168 proto);
75169 DUK_ASSERT(new_env != NULL);
75170
75171 /* It's important that duk_xdef_prop() is a 'raw define' so that any
75172 * properties in an ancestor are never an issue (they should never be
75173 * e.g. non-writable, but just in case).
75174 *
75175 * Because template objects are not visible to user code, the case
75176 * where .name is missing shouldn't happen in practice. It it does,
75177 * the name 'undefined' gets bound and maps to the closure (which is
75178 * a bit odd, but safe).
75179 */
75180 (void) duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_NAME);
75181 /* -> [ ... closure template env funcname ] */
75182 duk_dup_m4(ctx); /* -> [ ... closure template env funcname closure ] */
75183 duk_xdef_prop(ctx, -3, DUK_PROPDESC_FLAGS_NONE); /* -> [ ... closure template env ] */
75184 /* env[funcname] = closure */
75185
75186 /* [ ... closure template env ] */
75187
75188 DUK_HCOMPFUNC_SET_LEXENV(thr->heap, fun_clos, new_env);
75189 DUK_HCOMPFUNC_SET_VARENV(thr->heap, fun_clos, new_env);
75190 DUK_HOBJECT_INCREF(thr, new_env);
75191 DUK_HOBJECT_INCREF(thr, new_env);
75192 duk_pop(ctx);
75193
75194 /* [ ... closure template ] */
75195 }
75196 else
75197#endif /* DUK_USE_FUNC_NAME_PROPERTY */
75198 {
75199 /*
75200 * Other cases (function declaration, anonymous function expression,
75201 * strict direct eval code). The "outer" environment will be whatever
75202 * the caller gave us.
75203 */
75204
75205 DUK_HCOMPFUNC_SET_LEXENV(thr->heap, fun_clos, outer_lex_env);
75206 DUK_HCOMPFUNC_SET_VARENV(thr->heap, fun_clos, outer_lex_env);
75207 DUK_HOBJECT_INCREF(thr, outer_lex_env);
75208 DUK_HOBJECT_INCREF(thr, outer_lex_env);
75209
75210 /* [ ... closure template ] */
75211 }
75212 } else {
75213 /*
75214 * Function gets no new environment when called. This is the
75215 * case for global code, indirect eval code, and non-strict
75216 * direct eval code. There is no direct correspondence to the
75217 * E5 specification, as global/eval code is not exposed as a
75218 * function.
75219 */
75220
75221 DUK_ASSERT(!DUK_HOBJECT_HAS_NAMEBINDING(&fun_temp->obj));
75222
75223 DUK_HCOMPFUNC_SET_LEXENV(thr->heap, fun_clos, outer_lex_env);
75224 DUK_HCOMPFUNC_SET_VARENV(thr->heap, fun_clos, outer_var_env);
75225 DUK_HOBJECT_INCREF(thr, outer_lex_env); /* NULLs not allowed; asserted on entry */
75226 DUK_HOBJECT_INCREF(thr, outer_var_env);
75227 }
75228 DUK_DDD(DUK_DDDPRINT("closure varenv -> %!ipO, lexenv -> %!ipO",
75229 (duk_heaphdr *) fun_clos->var_env,
75230 (duk_heaphdr *) fun_clos->lex_env));
75231
75232 /* Call handling assumes this for all callable closures. */
75233 DUK_ASSERT(DUK_HCOMPFUNC_GET_LEXENV(thr->heap, fun_clos) != NULL);
75234 DUK_ASSERT(DUK_HCOMPFUNC_GET_VARENV(thr->heap, fun_clos) != NULL);
75235
75236 /*
75237 * Copy some internal properties directly
75238 *
75239 * The properties will be non-writable and non-enumerable, but
75240 * configurable.
75241 */
75242
75243 /* [ ... closure template ] */
75244
75245 DUK_DDD(DUK_DDDPRINT("copying properties: closure=%!iT, template=%!iT",
75246 (duk_tval *) duk_get_tval(ctx, -2),
75247 (duk_tval *) duk_get_tval(ctx, -1)));
75248
75249 for (i = 0; i < (duk_small_uint_t) (sizeof(duk__closure_copy_proplist) / sizeof(duk_uint16_t)); i++) {
75250 duk_small_int_t stridx = (duk_small_int_t) duk__closure_copy_proplist[i];
75251 if (duk_get_prop_stridx_short(ctx, -1, stridx)) {
75252 /* [ ... closure template val ] */
75253 DUK_DDD(DUK_DDDPRINT("copying property, stridx=%ld -> found", (long) stridx));
75254 duk_xdef_prop_stridx_short(ctx, -3, stridx, DUK_PROPDESC_FLAGS_C);
75255 } else {
75256 DUK_DDD(DUK_DDDPRINT("copying property, stridx=%ld -> not found", (long) stridx));
75257 duk_pop(ctx);
75258 }
75259 }
75260
75261 /*
75262 * "length" maps to number of formals (E5 Section 13.2) for function
75263 * declarations/expressions (non-bound functions). Note that 'nargs'
75264 * is NOT necessarily equal to the number of arguments. Use length
75265 * of _Formals; if missing, assume nargs matches .length.
75266 */
75267
75268 /* [ ... closure template ] */
75269
75270 /* XXX: these lookups should be just own property lookups instead of
75271 * looking up the inheritance chain.
75272 */
75273 if (duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_FORMALS)) {
75274 /* [ ... closure template formals ] */
75275 len_value = (duk_uint_t) duk_get_length(ctx, -1); /* could access duk_harray directly, not important */
75276 DUK_DD(DUK_DDPRINT("closure length from _Formals -> %ld", (long) len_value));
75277 } else {
75278 len_value = fun_temp->nargs;
75279 DUK_DD(DUK_DDPRINT("closure length defaulted from nargs -> %ld", (long) len_value));
75280 }
75281 duk_pop(ctx);
75282
75283 duk_push_uint(ctx, len_value); /* [ ... closure template len_value ] */
75284 duk_xdef_prop_stridx_short(ctx, -3, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_C);
75285
75286 /*
75287 * "prototype" is, by default, a fresh object with the "constructor"
75288 * property.
75289 *
75290 * Note that this creates a circular reference for every function
75291 * instance (closure) which prevents refcount-based collection of
75292 * function instances.
75293 *
75294 * XXX: Try to avoid creating the default prototype object, because
75295 * many functions are not used as constructors and the default
75296 * prototype is unnecessary. Perhaps it could be created on-demand
75297 * when it is first accessed?
75298 */
75299
75300 /* [ ... closure template ] */
75301
75302 if (add_auto_proto) {
75303 duk_push_object(ctx); /* -> [ ... closure template newobj ] */
75304 duk_dup_m3(ctx); /* -> [ ... closure template newobj closure ] */
75305 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_CONSTRUCTOR, DUK_PROPDESC_FLAGS_WC); /* -> [ ... closure template newobj ] */
75306 duk_compact(ctx, -1); /* compact the prototype */
75307 duk_xdef_prop_stridx_short(ctx, -3, DUK_STRIDX_PROTOTYPE, DUK_PROPDESC_FLAGS_W); /* -> [ ... closure template ] */
75308 }
75309
75310 /*
75311 * "arguments" and "caller" must be mapped to throwers for strict
75312 * mode and bound functions (E5 Section 15.3.5).
75313 *
75314 * XXX: This is expensive to have for every strict function instance.
75315 * Try to implement as virtual properties or on-demand created properties.
75316 */
75317
75318 /* [ ... closure template ] */
75319
75320 if (DUK_HOBJECT_HAS_STRICT(&fun_clos->obj)) {
75321 duk_xdef_prop_stridx_thrower(ctx, -2, DUK_STRIDX_CALLER);
75322 duk_xdef_prop_stridx_thrower(ctx, -2, DUK_STRIDX_LC_ARGUMENTS);
75323 } else {
75324#if defined(DUK_USE_NONSTD_FUNC_CALLER_PROPERTY)
75325 DUK_DDD(DUK_DDDPRINT("function is non-strict and non-standard 'caller' property in use, add initial 'null' value"));
75326 duk_push_null(ctx);
75327 duk_xdef_prop_stridx_short(ctx, -3, DUK_STRIDX_CALLER, DUK_PROPDESC_FLAGS_NONE);
75328#else
75329 DUK_DDD(DUK_DDDPRINT("function is non-strict and non-standard 'caller' property not used"));
75330#endif
75331 }
75332
75333 /*
75334 * "name" used to be non-standard but is now defined by ES2015.
75335 * In ES2015/ES2016 the .name property is configurable.
75336 */
75337
75338 /* [ ... closure template ] */
75339
75340#if defined(DUK_USE_FUNC_NAME_PROPERTY)
75341 /* XXX: Look for own property only; doesn't matter much because
75342 * templates are bare objects.
75343 */
75344 if (duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_NAME)) {
75345 /* [ ... closure template name ] */
75346 DUK_ASSERT(duk_is_string(ctx, -1));
75347 DUK_DD(DUK_DDPRINT("setting function instance name to %!T", duk_get_tval(ctx, -1)));
75348 duk_xdef_prop_stridx_short(ctx, -3, DUK_STRIDX_NAME, DUK_PROPDESC_FLAGS_C); /* -> [ ... closure template ] */
75349 } else {
75350 /* Anonymous functions don't have a .name in ES2015, so don't set
75351 * it on the instance either. The instance will then inherit
75352 * it from Function.prototype.name.
75353 */
75354 DUK_DD(DUK_DDPRINT("not setting function instance .name"));
75355 duk_pop(ctx);
75356 }
75357#endif
75358
75359 /*
75360 * Compact the closure, in most cases no properties will be added later.
75361 * Also, without this the closures end up having unused property slots
75362 * (e.g. in Duktape 0.9.0, 8 slots would be allocated and only 7 used).
75363 * A better future solution would be to allocate the closure directly
75364 * to correct size (and setup the properties directly without going
75365 * through the API).
75366 */
75367
75368 duk_compact(ctx, -2);
75369
75370 /*
75371 * Some assertions (E5 Section 13.2).
75372 */
75373
75374 DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(&fun_clos->obj) == DUK_HOBJECT_CLASS_FUNCTION);
75375 DUK_ASSERT(DUK_HOBJECT_GET_PROTOTYPE(thr->heap, &fun_clos->obj) == thr->builtins[DUK_BIDX_FUNCTION_PROTOTYPE]);
75376 DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(&fun_clos->obj));
75377 DUK_ASSERT(duk_has_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH) != 0);
75378 DUK_ASSERT(add_auto_proto == 0 || duk_has_prop_stridx(ctx, -2, DUK_STRIDX_PROTOTYPE) != 0);
75379 /* May be missing .name */
75380 DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(&fun_clos->obj) ||
75381 duk_has_prop_stridx(ctx, -2, DUK_STRIDX_CALLER) != 0);
75382 DUK_ASSERT(!DUK_HOBJECT_HAS_STRICT(&fun_clos->obj) ||
75383 duk_has_prop_stridx(ctx, -2, DUK_STRIDX_LC_ARGUMENTS) != 0);
75384
75385 /*
75386 * Finish
75387 */
75388
75389 /* [ ... closure template ] */
75390
75391 DUK_DDD(DUK_DDDPRINT("created function instance: template=%!iT -> closure=%!iT",
75392 (duk_tval *) duk_get_tval(ctx, -1),
75393 (duk_tval *) duk_get_tval(ctx, -2)));
75394
75395 duk_pop(ctx);
75396
75397 /* [ ... closure ] */
75398}
75399
75400/*
75401 * Delayed activation environment record initialization (for functions
75402 * with NEWENV).
75403 *
75404 * The non-delayed initialization is handled by duk_handle_call().
75405 */
75406
75407/* shared helper */
75408DUK_INTERNAL
75409duk_hobject *duk_create_activation_environment_record(duk_hthread *thr,
75410 duk_hobject *func,
75411 duk_size_t idx_bottom) {
75412 duk_context *ctx = (duk_context *) thr;
75413 duk_hobject *env;
75414 duk_hobject *parent;
75415 duk_hcompfunc *f;
75416
75417 DUK_ASSERT(thr != NULL);
75418 DUK_ASSERT(func != NULL);
75419
75420 f = (duk_hcompfunc *) func;
75421 parent = DUK_HCOMPFUNC_GET_LEXENV(thr->heap, f);
75422 if (!parent) {
75423 parent = thr->builtins[DUK_BIDX_GLOBAL_ENV];
75424 }
75425
75426 (void) duk_push_object_helper(ctx,
75427 DUK_HOBJECT_FLAG_EXTENSIBLE |
75428 DUK_HOBJECT_CLASS_AS_FLAGS(DUK_HOBJECT_CLASS_DECENV),
75429 -1); /* no prototype, updated below */
75430 env = duk_known_hobject(ctx, -1);
75431 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, env, parent); /* parent env is the prototype */
75432
75433 /* open scope information, for compiled functions only */
75434
75435 if (DUK_HOBJECT_IS_COMPFUNC(func)) {
75436 duk_push_hthread(ctx, thr);
75437 duk_xdef_prop_stridx_short_wec(ctx, -2, DUK_STRIDX_INT_THREAD);
75438 duk_push_hobject(ctx, func);
75439 duk_xdef_prop_stridx_short_wec(ctx, -2, DUK_STRIDX_INT_CALLEE);
75440 duk_push_size_t(ctx, idx_bottom);
75441 duk_xdef_prop_stridx_short_wec(ctx, -2, DUK_STRIDX_INT_REGBASE);
75442 }
75443
75444 return env;
75445}
75446
75447DUK_INTERNAL
75448void duk_js_init_activation_environment_records_delayed(duk_hthread *thr,
75449 duk_activation *act) {
75450 duk_context *ctx = (duk_context *) thr;
75451 duk_hobject *func;
75452 duk_hobject *env;
75453
75454 func = DUK_ACT_GET_FUNC(act);
75455 DUK_ASSERT(func != NULL);
75456 DUK_ASSERT(!DUK_HOBJECT_HAS_BOUNDFUNC(func)); /* bound functions are never in act 'func' */
75457
75458 /*
75459 * Delayed initialization only occurs for 'NEWENV' functions.
75460 */
75461
75462 DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
75463 DUK_ASSERT(act->lex_env == NULL);
75464 DUK_ASSERT(act->var_env == NULL);
75465
75466 env = duk_create_activation_environment_record(thr, func, act->idx_bottom);
75467 DUK_ASSERT(env != NULL);
75468
75469 DUK_DDD(DUK_DDDPRINT("created delayed fresh env: %!ipO", (duk_heaphdr *) env));
75470#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
75471 {
75472 duk_hobject *p = env;
75473 while (p) {
75474 DUK_DDD(DUK_DDDPRINT(" -> %!ipO", (duk_heaphdr *) p));
75475 p = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, p);
75476 }
75477 }
75478#endif
75479
75480 act->lex_env = env;
75481 act->var_env = env;
75482 DUK_HOBJECT_INCREF(thr, env); /* XXX: incref by count (here 2 times) */
75483 DUK_HOBJECT_INCREF(thr, env);
75484
75485 duk_pop(ctx);
75486}
75487
75488/*
75489 * Closing environment records.
75490 *
75491 * The environment record MUST be closed with the thread where its activation
75492 * is. In other words (if 'env' is open):
75493 *
75494 * - 'thr' must match _env.thread
75495 * - 'func' must match _env.callee
75496 * - 'regbase' must match _env.regbase
75497 *
75498 * These are not looked up from the env to minimize code size.
75499 *
75500 * XXX: should access the own properties directly instead of using the API
75501 */
75502
75503DUK_INTERNAL void duk_js_close_environment_record(duk_hthread *thr, duk_hobject *env, duk_hobject *func, duk_size_t regbase) {
75504 duk_context *ctx = (duk_context *) thr;
75505 duk_uint_fast32_t i;
75506
75507 DUK_ASSERT(thr != NULL);
75508 DUK_ASSERT(env != NULL);
75509 /* func is NULL for lightfuncs */
75510
75511 if (!DUK_HOBJECT_IS_DECENV(env) || DUK_HOBJECT_HAS_ENVRECCLOSED(env)) {
75512 DUK_DDD(DUK_DDDPRINT("environment record not a declarative record, "
75513 "or already closed: %!iO",
75514 (duk_heaphdr *) env));
75515 return;
75516 }
75517
75518 DUK_DDD(DUK_DDDPRINT("closing environment record: %!iO, func: %!iO, regbase: %ld",
75519 (duk_heaphdr *) env, (duk_heaphdr *) func, (long) regbase));
75520
75521 duk_push_hobject(ctx, env);
75522
75523 /* assertions: env must be closed in the same thread as where it runs */
75524#if defined(DUK_USE_ASSERTIONS)
75525 {
75526 /* [... env] */
75527
75528 if (duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_CALLEE)) {
75529 DUK_ASSERT(duk_is_object(ctx, -1));
75530 DUK_ASSERT(duk_get_hobject(ctx, -1) == (duk_hobject *) func);
75531 }
75532 duk_pop(ctx);
75533
75534 if (duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_THREAD)) {
75535 DUK_ASSERT(duk_is_object(ctx, -1));
75536 DUK_ASSERT(duk_get_hobject(ctx, -1) == (duk_hobject *) thr);
75537 }
75538 duk_pop(ctx);
75539
75540 if (duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_REGBASE)) {
75541 DUK_ASSERT(duk_is_number(ctx, -1));
75542 DUK_ASSERT(duk_get_number(ctx, -1) == (double) regbase);
75543 }
75544 duk_pop(ctx);
75545
75546 /* [... env] */
75547 }
75548#endif
75549
75550 if (func != NULL && DUK_HOBJECT_IS_COMPFUNC(func)) {
75551 duk_hobject *varmap;
75553 duk_tval *tv;
75554 duk_uint_t regnum;
75555
75556 /* XXX: additional conditions when to close variables? we don't want to do it
75557 * unless the environment may have "escaped" (referenced in a function closure).
75558 * With delayed environments, the existence is probably good enough of a check.
75559 */
75560
75561 /* XXX: any way to detect faster whether something needs to be closed?
75562 * We now look up _Callee and then skip the rest.
75563 */
75564
75565 /* Note: we rely on the _Varmap having a bunch of nice properties, like:
75566 * - being compacted and unmodified during this process
75567 * - not containing an array part
75568 * - having correct value types
75569 */
75570
75571 /* [... env] */
75572
75573 if (!duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_CALLEE)) {
75574 DUK_DDD(DUK_DDDPRINT("env has no callee property, nothing to close; re-delete the control properties just in case"));
75575 duk_pop(ctx);
75576 goto skip_varmap;
75577 }
75578
75579 /* [... env callee] */
75580
75581 if (!duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_VARMAP)) {
75582 DUK_DDD(DUK_DDDPRINT("callee has no varmap property, nothing to close; delete the control properties"));
75583 duk_pop_2(ctx);
75584 goto skip_varmap;
75585 }
75586 varmap = duk_require_hobject(ctx, -1);
75587 DUK_ASSERT(varmap != NULL);
75588
75589 DUK_DDD(DUK_DDDPRINT("varmap: %!O", (duk_heaphdr *) varmap));
75590
75591 /* [... env callee varmap] */
75592
75593 DUK_DDD(DUK_DDDPRINT("copying bound register values, %ld bound regs", (long) DUK_HOBJECT_GET_ENEXT(varmap)));
75594
75595 for (i = 0; i < (duk_uint_fast32_t) DUK_HOBJECT_GET_ENEXT(varmap); i++) {
75596 key = DUK_HOBJECT_E_GET_KEY(thr->heap, varmap, i);
75597 DUK_ASSERT(key != NULL); /* assume keys are compacted */
75598
75599 DUK_ASSERT(!DUK_HOBJECT_E_SLOT_IS_ACCESSOR(thr->heap, varmap, i)); /* assume plain values */
75600
75601 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, varmap, i);
75602 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv)); /* assume value is a number */
75603 regnum = (duk_uint_t) DUK_TVAL_GET_NUMBER(tv);
75604 DUK_ASSERT_DISABLE(regnum >= 0); /* unsigned */
75605 DUK_ASSERT(regnum < ((duk_hcompfunc *) func)->nregs); /* regnum is sane */
75606 DUK_ASSERT(thr->valstack + regbase + regnum >= thr->valstack);
75607 DUK_ASSERT(thr->valstack + regbase + regnum < thr->valstack_top);
75608
75609 /* XXX: slightly awkward */
75610 duk_push_hstring(ctx, key);
75611 duk_push_tval(ctx, thr->valstack + regbase + regnum);
75612 DUK_DDD(DUK_DDDPRINT("closing identifier '%s' -> reg %ld, value %!T",
75613 (const char *) duk_require_string(ctx, -2),
75614 (long) regnum,
75615 (duk_tval *) duk_get_tval(ctx, -1)));
75616
75617 /* [... env callee varmap key val] */
75618
75619 /* if property already exists, overwrites silently */
75620 duk_xdef_prop(ctx, -5, DUK_PROPDESC_FLAGS_WE); /* writable but not deletable */
75621 }
75622
75623 duk_pop_2(ctx);
75624
75625 /* [... env] */
75626 }
75627
75628 skip_varmap:
75629
75630 /* [... env] */
75631
75632 duk_del_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_CALLEE);
75633 duk_del_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_THREAD);
75634 duk_del_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_REGBASE);
75635
75636 duk_pop(ctx);
75637
75638 DUK_HOBJECT_SET_ENVRECCLOSED(env);
75639
75640 DUK_DDD(DUK_DDDPRINT("environment record after being closed: %!O",
75641 (duk_heaphdr *) env));
75642}
75643
75644/*
75645 * GETIDREF: a GetIdentifierReference-like helper.
75646 *
75647 * Provides a parent traversing lookup and a single level lookup
75648 * (for HasBinding).
75649 *
75650 * Instead of returning the value, returns a bunch of values allowing
75651 * the caller to read, write, or delete the binding. Value pointers
75652 * are duk_tval pointers which can be mutated directly as long as
75653 * refcounts are properly updated. Note that any operation which may
75654 * reallocate valstacks or compact objects may invalidate the returned
75655 * duk_tval (but not object) pointers, so caller must be very careful.
75656 *
75657 * If starting environment record 'env' is given, 'act' is ignored.
75658 * However, if 'env' is NULL, the caller may identify, in 'act', an
75659 * activation which hasn't had its declarative environment initialized
75660 * yet. The activation registers are then looked up, and its parent
75661 * traversed normally.
75662 *
75663 * The 'out' structure values are only valid if the function returns
75664 * success (non-zero).
75665 */
75666
75667/* lookup name from an open declarative record's registers */
75668DUK_LOCAL
75669duk_bool_t duk__getid_open_decl_env_regs(duk_hthread *thr,
75670 duk_hstring *name,
75671 duk_hobject *env,
75672 duk__id_lookup_result *out) {
75673 duk_hthread *env_thr;
75674 duk_hobject *env_func;
75675 duk_size_t env_regbase;
75676 duk_hobject *varmap;
75677 duk_tval *tv;
75678 duk_size_t reg_rel;
75679 duk_size_t idx;
75680
75681 DUK_ASSERT(thr != NULL);
75682 DUK_ASSERT(name != NULL);
75683 DUK_ASSERT(env != NULL);
75684 DUK_ASSERT(out != NULL);
75685
75686 DUK_ASSERT(DUK_HOBJECT_IS_DECENV(env));
75687
75688 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_CALLEE(thr));
75689 if (!tv) {
75690 /* env is closed, should be missing _Callee, _Thread, _Regbase */
75691 DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_CALLEE(thr)) == NULL);
75692 DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_THREAD(thr)) == NULL);
75693 DUK_ASSERT(duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_REGBASE(thr)) == NULL);
75694 return 0;
75695 }
75696
75697 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
75698 DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL);
75699 DUK_ASSERT(DUK_HOBJECT_IS_COMPFUNC(DUK_TVAL_GET_OBJECT(tv)));
75700 env_func = DUK_TVAL_GET_OBJECT(tv);
75701 DUK_ASSERT(env_func != NULL);
75702
75703 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env_func, DUK_HTHREAD_STRING_INT_VARMAP(thr));
75704 if (!tv) {
75705 return 0;
75706 }
75707 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
75708 varmap = DUK_TVAL_GET_OBJECT(tv);
75709 DUK_ASSERT(varmap != NULL);
75710
75711 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, varmap, name);
75712 if (!tv) {
75713 return 0;
75714 }
75715 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
75716 reg_rel = (duk_size_t) DUK_TVAL_GET_NUMBER(tv);
75717 DUK_ASSERT_DISABLE(reg_rel >= 0); /* unsigned */
75718 DUK_ASSERT(reg_rel < ((duk_hcompfunc *) env_func)->nregs);
75719
75720 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_THREAD(thr));
75721 DUK_ASSERT(tv != NULL);
75722 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
75723 DUK_ASSERT(DUK_TVAL_GET_OBJECT(tv) != NULL);
75724 DUK_ASSERT(DUK_HOBJECT_IS_THREAD(DUK_TVAL_GET_OBJECT(tv)));
75725 env_thr = (duk_hthread *) DUK_TVAL_GET_OBJECT(tv);
75726 DUK_ASSERT(env_thr != NULL);
75727
75728 /* Note: env_thr != thr is quite possible and normal, so careful
75729 * with what thread is used for valstack lookup.
75730 */
75731
75732 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_REGBASE(thr));
75733 DUK_ASSERT(tv != NULL);
75734 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
75735 env_regbase = (duk_size_t) DUK_TVAL_GET_NUMBER(tv);
75736
75737 idx = env_regbase + reg_rel;
75738 tv = env_thr->valstack + idx;
75739 DUK_ASSERT(tv >= env_thr->valstack && tv < env_thr->valstack_end); /* XXX: more accurate? */
75740
75741 out->value = tv;
75742 out->attrs = DUK_PROPDESC_FLAGS_W; /* registers are mutable, non-deletable */
75743 out->this_binding = NULL; /* implicit this value always undefined for
75744 * declarative environment records.
75745 */
75746 out->env = env;
75747 out->holder = NULL;
75748
75749 return 1;
75750}
75751
75752/* lookup name from current activation record's functions' registers */
75753DUK_LOCAL
75754duk_bool_t duk__getid_activation_regs(duk_hthread *thr,
75755 duk_hstring *name,
75756 duk_activation *act,
75757 duk__id_lookup_result *out) {
75758 duk_tval *tv;
75759 duk_hobject *func;
75760 duk_hobject *varmap;
75761 duk_size_t reg_rel;
75762 duk_size_t idx;
75763
75764 DUK_ASSERT(thr != NULL);
75765 DUK_ASSERT(name != NULL);
75766 DUK_ASSERT(act != NULL);
75767 DUK_ASSERT(out != NULL);
75768
75769 func = DUK_ACT_GET_FUNC(act);
75770 DUK_ASSERT(func != NULL);
75771 DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
75772
75773 if (!DUK_HOBJECT_IS_COMPFUNC(func)) {
75774 return 0;
75775 }
75776
75777 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, func, DUK_HTHREAD_STRING_INT_VARMAP(thr));
75778 if (!tv) {
75779 return 0;
75780 }
75781 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
75782 varmap = DUK_TVAL_GET_OBJECT(tv);
75783 DUK_ASSERT(varmap != NULL);
75784
75785 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, varmap, name);
75786 if (!tv) {
75787 return 0;
75788 }
75789 DUK_ASSERT(DUK_TVAL_IS_NUMBER(tv));
75790 reg_rel = (duk_size_t) DUK_TVAL_GET_NUMBER(tv);
75791 DUK_ASSERT_DISABLE(reg_rel >= 0);
75792 DUK_ASSERT(reg_rel < ((duk_hcompfunc *) func)->nregs);
75793
75794 idx = act->idx_bottom + reg_rel;
75795 DUK_ASSERT(idx >= act->idx_bottom);
75796 tv = thr->valstack + idx;
75797
75798 out->value = tv;
75799 out->attrs = DUK_PROPDESC_FLAGS_W; /* registers are mutable, non-deletable */
75800 out->this_binding = NULL; /* implicit this value always undefined for
75801 * declarative environment records.
75802 */
75803 out->env = NULL;
75804 out->holder = NULL;
75805
75806 return 1;
75807}
75808
75809DUK_LOCAL
75810duk_bool_t duk__get_identifier_reference(duk_hthread *thr,
75811 duk_hobject *env,
75812 duk_hstring *name,
75813 duk_activation *act,
75814 duk_bool_t parents,
75815 duk__id_lookup_result *out) {
75816 duk_tval *tv;
75817 duk_tval *tv_target;
75818 duk_tval tv_name;
75819 duk_uint_t sanity;
75820
75821 DUK_ASSERT(thr != NULL);
75822 DUK_ASSERT(env != NULL || act != NULL);
75823 DUK_ASSERT(name != NULL);
75824 DUK_ASSERT(out != NULL);
75825
75826 DUK_ASSERT(!env || DUK_HOBJECT_IS_ENV(env));
75827 DUK_ASSERT(!env || !DUK_HOBJECT_HAS_ARRAY_PART(env));
75828
75829 /*
75830 * Conceptually, we look for the identifier binding by starting from
75831 * 'env' and following to chain of environment records (represented
75832 * by the prototype chain).
75833 *
75834 * If 'env' is NULL, the current activation does not yet have an
75835 * allocated declarative environment record; this should be treated
75836 * exactly as if the environment record existed but had no bindings
75837 * other than register bindings.
75838 *
75839 * Note: we assume that with the DUK_HOBJECT_FLAG_NEWENV cleared
75840 * the environment will always be initialized immediately; hence
75841 * a NULL 'env' should only happen with the flag set. This is the
75842 * case for: (1) function calls, and (2) strict, direct eval calls.
75843 */
75844
75845 if (env == NULL && act != NULL) {
75846 duk_hobject *func;
75847 duk_hcompfunc *f;
75848
75849 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference: env is NULL, activation is non-NULL -> "
75850 "delayed env case, look up activation regs first"));
75851
75852 /*
75853 * Try registers
75854 */
75855
75856 if (duk__getid_activation_regs(thr, name, act, out)) {
75857 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
75858 "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O "
75859 "(found from register bindings when env=NULL)",
75860 (duk_heaphdr *) name, (duk_tval *) out->value,
75861 (long) out->attrs, (duk_tval *) out->this_binding,
75862 (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
75863 return 1;
75864 }
75865
75866 DUK_DDD(DUK_DDDPRINT("not found in current activation regs"));
75867
75868 /*
75869 * Not found in registers, proceed to the parent record.
75870 * Here we need to determine what the parent would be,
75871 * if 'env' was not NULL (i.e. same logic as when initializing
75872 * the record).
75873 *
75874 * Note that environment initialization is only deferred when
75875 * DUK_HOBJECT_HAS_NEWENV is set, and this only happens for:
75876 * - Function code
75877 * - Strict eval code
75878 *
75879 * We only need to check _Lexenv here; _Varenv exists only if it
75880 * differs from _Lexenv (and thus _Lexenv will also be present).
75881 */
75882
75883 if (!parents) {
75884 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference failed, no parent traversal "
75885 "(not found from register bindings when env=NULL)"));
75886 goto fail_not_found;
75887 }
75888
75889 func = DUK_ACT_GET_FUNC(act);
75890 DUK_ASSERT(func != NULL);
75891 DUK_ASSERT(DUK_HOBJECT_HAS_NEWENV(func));
75892 f = (duk_hcompfunc *) func;
75893
75894 env = DUK_HCOMPFUNC_GET_LEXENV(thr->heap, f);
75895 if (!env) {
75896 env = thr->builtins[DUK_BIDX_GLOBAL_ENV];
75897 }
75898
75899 DUK_DDD(DUK_DDDPRINT("continue lookup from env: %!iO",
75900 (duk_heaphdr *) env));
75901 }
75902
75903 /*
75904 * Prototype walking starting from 'env'.
75905 *
75906 * ('act' is not needed anywhere here.)
75907 */
75908
75909 sanity = DUK_HOBJECT_PROTOTYPE_CHAIN_SANITY;
75910 while (env != NULL) {
75911 duk_small_int_t cl;
75912 duk_int_t attrs;
75913
75914 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference, name=%!O, considering env=%p -> %!iO",
75915 (duk_heaphdr *) name,
75916 (void *) env,
75917 (duk_heaphdr *) env));
75918
75919 DUK_ASSERT(env != NULL);
75920 DUK_ASSERT(DUK_HOBJECT_IS_ENV(env));
75921 DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(env));
75922
75923 cl = DUK_HOBJECT_GET_CLASS_NUMBER(env);
75924 DUK_ASSERT(cl == DUK_HOBJECT_CLASS_OBJENV || cl == DUK_HOBJECT_CLASS_DECENV);
75925 if (cl == DUK_HOBJECT_CLASS_DECENV) {
75926 /*
75927 * Declarative environment record.
75928 *
75929 * Identifiers can never be stored in ancestors and are
75930 * always plain values, so we can use an internal helper
75931 * and access the value directly with an duk_tval ptr.
75932 *
75933 * A closed environment is only indicated by it missing
75934 * the "book-keeping" properties required for accessing
75935 * register-bound variables.
75936 */
75937
75938 if (DUK_HOBJECT_HAS_ENVRECCLOSED(env)) {
75939 /* already closed */
75940 goto skip_regs;
75941 }
75942
75943 if (duk__getid_open_decl_env_regs(thr, name, env, out)) {
75944 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
75945 "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O "
75946 "(declarative environment record, scope open, found in regs)",
75947 (duk_heaphdr *) name, (duk_tval *) out->value,
75948 (long) out->attrs, (duk_tval *) out->this_binding,
75949 (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
75950 return 1;
75951 }
75952 skip_regs:
75953
75954 tv = duk_hobject_find_existing_entry_tval_ptr_and_attrs(thr->heap, env, name, &attrs);
75955 if (tv) {
75956 out->value = tv;
75957 out->attrs = attrs;
75958 out->this_binding = NULL; /* implicit this value always undefined for
75959 * declarative environment records.
75960 */
75961 out->env = env;
75962 out->holder = env;
75963
75964 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
75965 "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O "
75966 "(declarative environment record, found in properties)",
75967 (duk_heaphdr *) name, (duk_tval *) out->value,
75968 (long) out->attrs, (duk_tval *) out->this_binding,
75969 (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
75970 return 1;
75971 }
75972 } else {
75973 /*
75974 * Object environment record.
75975 *
75976 * Binding (target) object is an external, uncontrolled object.
75977 * Identifier may be bound in an ancestor property, and may be
75978 * an accessor. Target can also be a Proxy which we must support
75979 * here.
75980 */
75981
75982 /* XXX: we could save space by using _Target OR _This. If _Target, assume
75983 * this binding is undefined. If _This, assumes this binding is _This, and
75984 * target is also _This. One property would then be enough.
75985 */
75986
75987 duk_hobject *target;
75988 duk_bool_t found;
75989
75990 DUK_ASSERT(cl == DUK_HOBJECT_CLASS_OBJENV);
75991
75992 tv_target = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_TARGET(thr));
75993 DUK_ASSERT(tv_target != NULL);
75994 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv_target));
75995 target = DUK_TVAL_GET_OBJECT(tv_target);
75996 DUK_ASSERT(target != NULL);
75997
75998 /* Target may be a Proxy or property may be an accessor, so we must
75999 * use an actual, Proxy-aware hasprop check here.
76000 *
76001 * out->holder is NOT set to the actual duk_hobject where the
76002 * property is found, but rather the object binding target object.
76003 */
76004
76005 if (DUK_HOBJECT_HAS_EXOTIC_PROXYOBJ(target)) {
76006 DUK_ASSERT(name != NULL);
76007 DUK_TVAL_SET_STRING(&tv_name, name);
76008
76009 found = duk_hobject_hasprop(thr, tv_target, &tv_name);
76010 } else {
76011 /* XXX: duk_hobject_hasprop() would be correct for
76012 * non-Proxy objects too, but it is about ~20-25%
76013 * slower at present so separate code paths for
76014 * Proxy and non-Proxy now.
76015 */
76016 found = duk_hobject_hasprop_raw(thr, target, name);
76017 }
76018
76019 if (found) {
76020 out->value = NULL; /* can't get value, may be accessor */
76021 out->attrs = 0; /* irrelevant when out->value == NULL */
76022 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_THIS(thr));
76023 out->this_binding = tv; /* may be NULL */
76024 out->env = env;
76025 out->holder = target;
76026
76027 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference successful: "
76028 "name=%!O -> value=%!T, attrs=%ld, this=%!T, env=%!O, holder=%!O "
76029 "(object environment record)",
76030 (duk_heaphdr *) name, (duk_tval *) out->value,
76031 (long) out->attrs, (duk_tval *) out->this_binding,
76032 (duk_heaphdr *) out->env, (duk_heaphdr *) out->holder));
76033 return 1;
76034 }
76035 }
76036
76037 if (!parents) {
76038 DUK_DDD(DUK_DDDPRINT("duk__get_identifier_reference failed, no parent traversal "
76039 "(not found from first traversed env)"));
76040 goto fail_not_found;
76041 }
76042
76043 if (sanity-- == 0) {
76044 DUK_ERROR_RANGE(thr, DUK_STR_PROTOTYPE_CHAIN_LIMIT);
76045 }
76046 env = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, env);
76047 };
76048
76049 /*
76050 * Not found (even in global object)
76051 */
76052
76053 fail_not_found:
76054 return 0;
76055}
76056
76057/*
76058 * HASVAR: check identifier binding from a given environment record
76059 * without traversing its parents.
76060 *
76061 * This primitive is not exposed to user code as such, but is used
76062 * internally for e.g. declaration binding instantiation.
76063 *
76064 * See E5 Sections:
76065 * 10.2.1.1.1 HasBinding(N)
76066 * 10.2.1.2.1 HasBinding(N)
76067 *
76068 * Note: strictness has no bearing on this check. Hence we don't take
76069 * a 'strict' parameter.
76070 */
76071
76072#if 0 /*unused*/
76073DUK_INTERNAL
76074duk_bool_t duk_js_hasvar_envrec(duk_hthread *thr,
76075 duk_hobject *env,
76076 duk_hstring *name) {
76078 duk_bool_t parents;
76079
76080 DUK_DDD(DUK_DDDPRINT("hasvar: thr=%p, env=%p, name=%!O "
76081 "(env -> %!dO)",
76082 (void *) thr, (void *) env, (duk_heaphdr *) name,
76083 (duk_heaphdr *) env));
76084
76085 DUK_ASSERT(thr != NULL);
76086 DUK_ASSERT(env != NULL);
76087 DUK_ASSERT(name != NULL);
76088
76089 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env);
76090 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
76091
76092 DUK_ASSERT(DUK_HOBJECT_IS_ENV(env));
76093 DUK_ASSERT(!DUK_HOBJECT_HAS_ARRAY_PART(env));
76094
76095 /* lookup results is ignored */
76096 parents = 0;
76097 return duk__get_identifier_reference(thr, env, name, NULL, parents, &ref);
76098}
76099#endif
76100
76101/*
76102 * GETVAR
76103 *
76104 * See E5 Sections:
76105 * 11.1.2 Identifier Reference
76106 * 10.3.1 Identifier Resolution
76107 * 11.13.1 Simple Assignment [example of where the Reference is GetValue'd]
76108 * 8.7.1 GetValue (V)
76109 * 8.12.1 [[GetOwnProperty]] (P)
76110 * 8.12.2 [[GetProperty]] (P)
76111 * 8.12.3 [[Get]] (P)
76112 *
76113 * If 'throw' is true, always leaves two values on top of stack: [val this].
76114 *
76115 * If 'throw' is false, returns 0 if identifier cannot be resolved, and the
76116 * stack will be unaffected in this case. If identifier is resolved, returns
76117 * 1 and leaves [val this] on top of stack.
76118 *
76119 * Note: the 'strict' flag of a reference returned by GetIdentifierReference
76120 * is ignored by GetValue. Hence we don't take a 'strict' parameter.
76121 *
76122 * The 'throw' flag is needed for implementing 'typeof' for an unreferenced
76123 * identifier. An unreference identifier in other contexts generates a
76124 * ReferenceError.
76125 */
76126
76127DUK_LOCAL
76128duk_bool_t duk__getvar_helper(duk_hthread *thr,
76129 duk_hobject *env,
76130 duk_activation *act,
76131 duk_hstring *name,
76132 duk_bool_t throw_flag) {
76133 duk_context *ctx = (duk_context *) thr;
76135 duk_tval tv_tmp_obj;
76136 duk_tval tv_tmp_key;
76137 duk_bool_t parents;
76138
76139 DUK_DDD(DUK_DDDPRINT("getvar: thr=%p, env=%p, act=%p, name=%!O "
76140 "(env -> %!dO)",
76141 (void *) thr, (void *) env, (void *) act,
76142 (duk_heaphdr *) name, (duk_heaphdr *) env));
76143
76144 DUK_ASSERT(thr != NULL);
76145 DUK_ASSERT(name != NULL);
76146 /* env and act may be NULL */
76147
76148 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env);
76149 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
76150
76151 parents = 1; /* follow parent chain */
76152 if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) {
76153 if (ref.value) {
76154 DUK_ASSERT(ref.this_binding == NULL); /* always for register bindings */
76155 duk_push_tval(ctx, ref.value);
76156 duk_push_undefined(ctx);
76157 } else {
76158 DUK_ASSERT(ref.holder != NULL);
76159
76160 /* Note: getprop may invoke any getter and invalidate any
76161 * duk_tval pointers, so this must be done first.
76162 */
76163
76164 if (ref.this_binding) {
76165 duk_push_tval(ctx, ref.this_binding);
76166 } else {
76167 duk_push_undefined(ctx);
76168 }
76169
76170 DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder);
76171 DUK_TVAL_SET_STRING(&tv_tmp_key, name);
76172 (void) duk_hobject_getprop(thr, &tv_tmp_obj, &tv_tmp_key); /* [this value] */
76173
76174 /* ref.value, ref.this.binding invalidated here by getprop call */
76175
76176 duk_insert(ctx, -2); /* [this value] -> [value this] */
76177 }
76178
76179 return 1;
76180 } else {
76181 if (throw_flag) {
76182 DUK_ERROR_FMT1(thr, DUK_ERR_REFERENCE_ERROR,
76183 "identifier '%s' undefined",
76184 (const char *) DUK_HSTRING_GET_DATA(name));
76185 }
76186
76187 return 0;
76188 }
76189}
76190
76191DUK_INTERNAL
76192duk_bool_t duk_js_getvar_envrec(duk_hthread *thr,
76193 duk_hobject *env,
76194 duk_hstring *name,
76195 duk_bool_t throw_flag) {
76196 return duk__getvar_helper(thr, env, NULL, name, throw_flag);
76197}
76198
76199DUK_INTERNAL
76200duk_bool_t duk_js_getvar_activation(duk_hthread *thr,
76201 duk_activation *act,
76202 duk_hstring *name,
76203 duk_bool_t throw_flag) {
76204 DUK_ASSERT(act != NULL);
76205 return duk__getvar_helper(thr, act->lex_env, act, name, throw_flag);
76206}
76207
76208/*
76209 * PUTVAR
76210 *
76211 * See E5 Sections:
76212 * 11.1.2 Identifier Reference
76213 * 10.3.1 Identifier Resolution
76214 * 11.13.1 Simple Assignment [example of where the Reference is PutValue'd]
76215 * 8.7.2 PutValue (V,W) [see especially step 3.b, undefined -> automatic global in non-strict mode]
76216 * 8.12.4 [[CanPut]] (P)
76217 * 8.12.5 [[Put]] (P)
76218 *
76219 * Note: may invalidate any valstack (or object) duk_tval pointers because
76220 * putting a value may reallocate any object or any valstack. Caller beware.
76221 */
76222
76223DUK_LOCAL
76224void duk__putvar_helper(duk_hthread *thr,
76225 duk_hobject *env,
76226 duk_activation *act,
76227 duk_hstring *name,
76228 duk_tval *val,
76229 duk_bool_t strict) {
76231 duk_tval tv_tmp_obj;
76232 duk_tval tv_tmp_key;
76233 duk_bool_t parents;
76234
76235 DUK_DDD(DUK_DDDPRINT("putvar: thr=%p, env=%p, act=%p, name=%!O, val=%p, strict=%ld "
76236 "(env -> %!dO, val -> %!T)",
76237 (void *) thr, (void *) env, (void *) act,
76238 (duk_heaphdr *) name, (void *) val, (long) strict,
76239 (duk_heaphdr *) env, (duk_tval *) val));
76240
76241 DUK_ASSERT(thr != NULL);
76242 DUK_ASSERT(name != NULL);
76243 DUK_ASSERT(val != NULL);
76244 /* env and act may be NULL */
76245
76246 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(env);
76247 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
76248 DUK_ASSERT_REFCOUNT_NONZERO_TVAL(val);
76249
76250 /*
76251 * In strict mode E5 protects 'eval' and 'arguments' from being
76252 * assigned to (or even declared anywhere). Attempt to do so
76253 * should result in a compile time SyntaxError. See the internal
76254 * design documentation for details.
76255 *
76256 * Thus, we should never come here, run-time, for strict code,
76257 * and name 'eval' or 'arguments'.
76258 */
76259
76260 DUK_ASSERT(!strict ||
76261 (name != DUK_HTHREAD_STRING_EVAL(thr) &&
76262 name != DUK_HTHREAD_STRING_LC_ARGUMENTS(thr)));
76263
76264 /*
76265 * Lookup variable and update in-place if found.
76266 */
76267
76268 parents = 1; /* follow parent chain */
76269
76270 if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) {
76271 if (ref.value && (ref.attrs & DUK_PROPDESC_FLAG_WRITABLE)) {
76272 /* Update duk_tval in-place if pointer provided and the
76273 * property is writable. If the property is not writable
76274 * (immutable binding), use duk_hobject_putprop() which
76275 * will respect mutability.
76276 */
76277 duk_tval *tv_val;
76278
76279 DUK_ASSERT(ref.this_binding == NULL); /* always for register bindings */
76280
76281 tv_val = ref.value;
76282 DUK_ASSERT(tv_val != NULL);
76283 DUK_TVAL_SET_TVAL_UPDREF(thr, tv_val, val); /* side effects */
76284
76285 /* ref.value and ref.this_binding invalidated here */
76286 } else {
76287 DUK_ASSERT(ref.holder != NULL);
76288
76289 DUK_TVAL_SET_OBJECT(&tv_tmp_obj, ref.holder);
76290 DUK_TVAL_SET_STRING(&tv_tmp_key, name);
76291 (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, val, strict);
76292
76293 /* ref.value and ref.this_binding invalidated here */
76294 }
76295
76296 return;
76297 }
76298
76299 /*
76300 * Not found: write to global object (non-strict) or ReferenceError
76301 * (strict); see E5 Section 8.7.2, step 3.
76302 */
76303
76304 if (strict) {
76305 DUK_DDD(DUK_DDDPRINT("identifier binding not found, strict => reference error"));
76306 DUK_ERROR_FMT1(thr, DUK_ERR_REFERENCE_ERROR,
76307 "identifier '%s' undefined",
76308 (const char *) DUK_HSTRING_GET_DATA(name));
76309 }
76310
76311 DUK_DDD(DUK_DDDPRINT("identifier binding not found, not strict => set to global"));
76312
76313 DUK_TVAL_SET_OBJECT(&tv_tmp_obj, thr->builtins[DUK_BIDX_GLOBAL]);
76314 DUK_TVAL_SET_STRING(&tv_tmp_key, name);
76315 (void) duk_hobject_putprop(thr, &tv_tmp_obj, &tv_tmp_key, val, 0); /* 0 = no throw */
76316
76317 /* NB: 'val' may be invalidated here because put_value may realloc valstack,
76318 * caller beware.
76319 */
76320}
76321
76322DUK_INTERNAL
76323void duk_js_putvar_envrec(duk_hthread *thr,
76324 duk_hobject *env,
76325 duk_hstring *name,
76326 duk_tval *val,
76327 duk_bool_t strict) {
76328 duk__putvar_helper(thr, env, NULL, name, val, strict);
76329}
76330
76331DUK_INTERNAL
76332void duk_js_putvar_activation(duk_hthread *thr,
76333 duk_activation *act,
76334 duk_hstring *name,
76335 duk_tval *val,
76336 duk_bool_t strict) {
76337 DUK_ASSERT(act != NULL);
76338 duk__putvar_helper(thr, act->lex_env, act, name, val, strict);
76339}
76340
76341/*
76342 * DELVAR
76343 *
76344 * See E5 Sections:
76345 * 11.4.1 The delete operator
76346 * 10.2.1.1.5 DeleteBinding (N) [declarative environment record]
76347 * 10.2.1.2.5 DeleteBinding (N) [object environment record]
76348 *
76349 * Variable bindings established inside eval() are deletable (configurable),
76350 * other bindings are not, including variables declared in global level.
76351 * Registers are always non-deletable, and the deletion of other bindings
76352 * is controlled by the configurable flag.
76353 *
76354 * For strict mode code, the 'delete' operator should fail with a compile
76355 * time SyntaxError if applied to identifiers. Hence, no strict mode
76356 * run-time deletion of identifiers should ever happen. This function
76357 * should never be called from strict mode code!
76358 */
76359
76360DUK_LOCAL
76361duk_bool_t duk__delvar_helper(duk_hthread *thr,
76362 duk_hobject *env,
76363 duk_activation *act,
76364 duk_hstring *name) {
76366 duk_bool_t parents;
76367
76368 DUK_DDD(DUK_DDDPRINT("delvar: thr=%p, env=%p, act=%p, name=%!O "
76369 "(env -> %!dO)",
76370 (void *) thr, (void *) env, (void *) act,
76371 (duk_heaphdr *) name, (duk_heaphdr *) env));
76372
76373 DUK_ASSERT(thr != NULL);
76374 DUK_ASSERT(name != NULL);
76375 /* env and act may be NULL */
76376
76377 DUK_ASSERT_REFCOUNT_NONZERO_HEAPHDR(name);
76378
76379 parents = 1; /* follow parent chain */
76380
76381 if (duk__get_identifier_reference(thr, env, name, act, parents, &ref)) {
76382 if (ref.value && !(ref.attrs & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
76383 /* Identifier found in registers (always non-deletable)
76384 * or declarative environment record and non-configurable.
76385 */
76386 return 0;
76387 }
76388 DUK_ASSERT(ref.holder != NULL);
76389
76390 return duk_hobject_delprop_raw(thr, ref.holder, name, 0);
76391 }
76392
76393 /*
76394 * Not found (even in global object).
76395 *
76396 * In non-strict mode this is a silent SUCCESS (!), see E5 Section 11.4.1,
76397 * step 3.b. In strict mode this case is a compile time SyntaxError so
76398 * we should not come here.
76399 */
76400
76401 DUK_DDD(DUK_DDDPRINT("identifier to be deleted not found: name=%!O "
76402 "(treated as silent success)",
76403 (duk_heaphdr *) name));
76404 return 1;
76405}
76406
76407#if 0 /*unused*/
76408DUK_INTERNAL
76409duk_bool_t duk_js_delvar_envrec(duk_hthread *thr,
76410 duk_hobject *env,
76411 duk_hstring *name) {
76412 return duk__delvar_helper(thr, env, NULL, name);
76413}
76414#endif
76415
76416DUK_INTERNAL
76417duk_bool_t duk_js_delvar_activation(duk_hthread *thr,
76418 duk_activation *act,
76419 duk_hstring *name) {
76420 DUK_ASSERT(act != NULL);
76421 return duk__delvar_helper(thr, act->lex_env, act, name);
76422}
76423
76424/*
76425 * DECLVAR
76426 *
76427 * See E5 Sections:
76428 * 10.4.3 Entering Function Code
76429 * 10.5 Declaration Binding Instantion
76430 * 12.2 Variable Statement
76431 * 11.1.2 Identifier Reference
76432 * 10.3.1 Identifier Resolution
76433 *
76434 * Variable declaration behavior is mainly discussed in Section 10.5,
76435 * and is not discussed in the execution semantics (Sections 11-13).
76436 *
76437 * Conceptually declarations happen when code (global, eval, function)
76438 * is entered, before any user code is executed. In practice, register-
76439 * bound identifiers are 'declared' automatically (by virtue of being
76440 * allocated to registers with the initial value 'undefined'). Other
76441 * identifiers are declared in the function prologue with this primitive.
76442 *
76443 * Since non-register bindings eventually back to an internal object's
76444 * properties, the 'prop_flags' argument is used to specify binding
76445 * type:
76446 *
76447 * - Immutable binding: set DUK_PROPDESC_FLAG_WRITABLE to false
76448 * - Non-deletable binding: set DUK_PROPDESC_FLAG_CONFIGURABLE to false
76449 * - The flag DUK_PROPDESC_FLAG_ENUMERABLE should be set, although it
76450 * doesn't really matter for internal objects
76451 *
76452 * All bindings are non-deletable mutable bindings except:
76453 *
76454 * - Declarations in eval code (mutable, deletable)
76455 * - 'arguments' binding in strict function code (immutable)
76456 * - Function name binding of a function expression (immutable)
76457 *
76458 * Declarations may go to declarative environment records (always
76459 * so for functions), but may also go to object environment records
76460 * (e.g. global code). The global object environment has special
76461 * behavior when re-declaring a function (but not a variable); see
76462 * E5.1 specification, Section 10.5, step 5.e.
76463 *
76464 * Declarations always go to the 'top-most' environment record, i.e.
76465 * we never check the record chain. It's not an error even if a
76466 * property (even an immutable or non-deletable one) of the same name
76467 * already exists.
76468 *
76469 * If a declared variable already exists, its value needs to be updated
76470 * (if possible). Returns 1 if a PUTVAR needs to be done by the caller;
76471 * otherwise returns 0.
76472 */
76473
76474DUK_LOCAL
76475duk_bool_t duk__declvar_helper(duk_hthread *thr,
76476 duk_hobject *env,
76477 duk_hstring *name,
76478 duk_tval *val,
76479 duk_small_int_t prop_flags,
76480 duk_bool_t is_func_decl) {
76481 duk_context *ctx = (duk_context *) thr;
76482 duk_hobject *holder;
76483 duk_bool_t parents;
76485 duk_tval *tv;
76486
76487 DUK_DDD(DUK_DDDPRINT("declvar: thr=%p, env=%p, name=%!O, val=%!T, prop_flags=0x%08lx, is_func_decl=%ld "
76488 "(env -> %!iO)",
76489 (void *) thr, (void *) env, (duk_heaphdr *) name,
76490 (duk_tval *) val, (unsigned long) prop_flags,
76491 (unsigned int) is_func_decl, (duk_heaphdr *) env));
76492
76493 DUK_ASSERT(thr != NULL);
76494 DUK_ASSERT(env != NULL);
76495 DUK_ASSERT(name != NULL);
76496 DUK_ASSERT(val != NULL);
76497
76498 /* Note: in strict mode the compiler should reject explicit
76499 * declaration of 'eval' or 'arguments'. However, internal
76500 * bytecode may declare 'arguments' in the function prologue.
76501 * We don't bother checking (or asserting) for these now.
76502 */
76503
76504 /* Note: val is a stable duk_tval pointer. The caller makes
76505 * a value copy into its stack frame, so 'tv_val' is not subject
76506 * to side effects here.
76507 */
76508
76509 /*
76510 * Check whether already declared.
76511 *
76512 * We need to check whether the binding exists in the environment
76513 * without walking its parents. However, we still need to check
76514 * register-bound identifiers and the prototype chain of an object
76515 * environment target object.
76516 */
76517
76518 parents = 0; /* just check 'env' */
76519 if (duk__get_identifier_reference(thr, env, name, NULL, parents, &ref)) {
76520 duk_int_t e_idx;
76521 duk_int_t h_idx;
76522 duk_small_int_t flags;
76523
76524 /*
76525 * Variable already declared, ignore re-declaration.
76526 * The only exception is the updated behavior of E5.1 for
76527 * global function declarations, E5.1 Section 10.5, step 5.e.
76528 * This behavior does not apply to global variable declarations.
76529 */
76530
76531 if (!(is_func_decl && env == thr->builtins[DUK_BIDX_GLOBAL_ENV])) {
76532 DUK_DDD(DUK_DDDPRINT("re-declare a binding, ignoring"));
76533 return 1; /* 1 -> needs a PUTVAR */
76534 }
76535
76536 /*
76537 * Special behavior in E5.1.
76538 *
76539 * Note that even though parents == 0, the conflicting property
76540 * may be an inherited property (currently our global object's
76541 * prototype is Object.prototype). Step 5.e first operates on
76542 * the existing property (which is potentially in an ancestor)
76543 * and then defines a new property in the global object (and
76544 * never modifies the ancestor).
76545 *
76546 * Also note that this logic would become even more complicated
76547 * if the conflicting property might be a virtual one. Object
76548 * prototype has no virtual properties, though.
76549 *
76550 * XXX: this is now very awkward, rework.
76551 */
76552
76553 DUK_DDD(DUK_DDDPRINT("re-declare a function binding in global object, "
76554 "updated E5.1 processing"));
76555
76556 DUK_ASSERT(ref.holder != NULL);
76557 holder = ref.holder;
76558
76559 /* holder will be set to the target object, not the actual object
76560 * where the property was found (see duk__get_identifier_reference()).
76561 */
76562 DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(holder) == DUK_HOBJECT_CLASS_GLOBAL);
76563 DUK_ASSERT(!DUK_HOBJECT_HAS_EXOTIC_ARRAY(holder)); /* global object doesn't have array part */
76564
76565 /* XXX: use a helper for prototype traversal; no loop check here */
76566 /* must be found: was found earlier, and cannot be inherited */
76567 for (;;) {
76568 DUK_ASSERT(holder != NULL);
76569 duk_hobject_find_existing_entry(thr->heap, holder, name, &e_idx, &h_idx);
76570 if (e_idx >= 0) {
76571 break;
76572 }
76573 /* SCANBUILD: NULL pointer dereference, doesn't actually trigger,
76574 * asserted above.
76575 */
76576 holder = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, holder);
76577 }
76578 DUK_ASSERT(holder != NULL);
76579 DUK_ASSERT(e_idx >= 0);
76580 /* SCANBUILD: scan-build produces a NULL pointer dereference warning
76581 * below; it never actually triggers because holder is actually never
76582 * NULL.
76583 */
76584
76585 /* ref.holder is global object, holder is the object with the
76586 * conflicting property.
76587 */
76588
76589 flags = DUK_HOBJECT_E_GET_FLAGS(thr->heap, holder, e_idx);
76590 if (!(flags & DUK_PROPDESC_FLAG_CONFIGURABLE)) {
76591 if (flags & DUK_PROPDESC_FLAG_ACCESSOR) {
76592 DUK_DDD(DUK_DDDPRINT("existing property is a non-configurable "
76593 "accessor -> reject"));
76594 goto fail_existing_attributes;
76595 }
76596 if (!((flags & DUK_PROPDESC_FLAG_WRITABLE) &&
76597 (flags & DUK_PROPDESC_FLAG_ENUMERABLE))) {
76598 DUK_DDD(DUK_DDDPRINT("existing property is a non-configurable "
76599 "plain property which is not writable and "
76600 "enumerable -> reject"));
76601 goto fail_existing_attributes;
76602 }
76603
76604 DUK_DDD(DUK_DDDPRINT("existing property is not configurable but "
76605 "is plain, enumerable, and writable -> "
76606 "allow redeclaration"));
76607 }
76608
76609 if (holder == ref.holder) {
76610 /* XXX: if duk_hobject_define_property_internal() was updated
76611 * to handle a pre-existing accessor property, this would be
76612 * a simple call (like for the ancestor case).
76613 */
76614 DUK_DDD(DUK_DDDPRINT("redefine, offending property in global object itself"));
76615
76616 if (flags & DUK_PROPDESC_FLAG_ACCESSOR) {
76617 duk_hobject *tmp;
76618
76619 tmp = DUK_HOBJECT_E_GET_VALUE_GETTER(thr->heap, holder, e_idx);
76620 DUK_HOBJECT_E_SET_VALUE_GETTER(thr->heap, holder, e_idx, NULL);
76621 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
76622 DUK_UNREF(tmp);
76623 tmp = DUK_HOBJECT_E_GET_VALUE_SETTER(thr->heap, holder, e_idx);
76624 DUK_HOBJECT_E_SET_VALUE_SETTER(thr->heap, holder, e_idx, NULL);
76625 DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp);
76626 DUK_UNREF(tmp);
76627 } else {
76628 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, holder, e_idx);
76629 DUK_TVAL_SET_UNDEFINED_UPDREF(thr, tv);
76630 }
76631
76632 /* Here val would be potentially invalid if we didn't make
76633 * a value copy at the caller.
76634 */
76635
76636 tv = DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, holder, e_idx);
76637 DUK_TVAL_SET_TVAL(tv, val);
76638 DUK_TVAL_INCREF(thr, tv);
76639 DUK_HOBJECT_E_SET_FLAGS(thr->heap, holder, e_idx, prop_flags);
76640
76641 DUK_DDD(DUK_DDDPRINT("updated global binding, final result: "
76642 "value -> %!T, prop_flags=0x%08lx",
76643 (duk_tval *) DUK_HOBJECT_E_GET_VALUE_TVAL_PTR(thr->heap, holder, e_idx),
76644 (unsigned long) prop_flags));
76645 } else {
76646 DUK_DDD(DUK_DDDPRINT("redefine, offending property in ancestor"));
76647
76648 DUK_ASSERT(ref.holder == thr->builtins[DUK_BIDX_GLOBAL]);
76649 duk_push_tval(ctx, val);
76650 duk_hobject_define_property_internal(thr, ref.holder, name, prop_flags);
76651 }
76652
76653 return 0;
76654 }
76655
76656 /*
76657 * Not found (in registers or record objects). Declare
76658 * to current variable environment.
76659 */
76660
76661 /*
76662 * Get holder object
76663 */
76664
76665 if (DUK_HOBJECT_IS_DECENV(env)) {
76666 holder = env;
76667 } else {
76668 DUK_ASSERT(DUK_HOBJECT_IS_OBJENV(env));
76669
76670 tv = duk_hobject_find_existing_entry_tval_ptr(thr->heap, env, DUK_HTHREAD_STRING_INT_TARGET(thr));
76671 DUK_ASSERT(tv != NULL);
76672 DUK_ASSERT(DUK_TVAL_IS_OBJECT(tv));
76673 holder = DUK_TVAL_GET_OBJECT(tv);
76674 DUK_ASSERT(holder != NULL);
76675 }
76676
76677 /*
76678 * Define new property
76679 *
76680 * Note: this may fail if the holder is not extensible.
76681 */
76682
76683 /* XXX: this is awkward as we use an internal method which doesn't handle
76684 * extensibility etc correctly. Basically we'd want to do a [[DefineOwnProperty]]
76685 * or Object.defineProperty() here.
76686 */
76687
76688 if (!DUK_HOBJECT_HAS_EXTENSIBLE(holder)) {
76689 goto fail_not_extensible;
76690 }
76691
76692 duk_push_hobject(ctx, holder);
76693 duk_push_hstring(ctx, name);
76694 duk_push_tval(ctx, val);
76695 duk_xdef_prop(ctx, -3, prop_flags); /* [holder name val] -> [holder] */
76696 duk_pop(ctx);
76697
76698 return 0;
76699
76700 fail_existing_attributes:
76701 fail_not_extensible:
76702 DUK_ERROR_TYPE(thr, "declaration failed");
76703 return 0;
76704}
76705
76706DUK_INTERNAL
76707duk_bool_t duk_js_declvar_activation(duk_hthread *thr,
76708 duk_activation *act,
76709 duk_hstring *name,
76710 duk_tval *val,
76711 duk_small_int_t prop_flags,
76712 duk_bool_t is_func_decl) {
76713 duk_hobject *env;
76714 duk_tval tv_val_copy;
76715
76716 /*
76717 * Make a value copy of the input val. This ensures that
76718 * side effects cannot invalidate the pointer.
76719 */
76720
76721 DUK_TVAL_SET_TVAL(&tv_val_copy, val);
76722 val = &tv_val_copy;
76723
76724 /*
76725 * Delayed env creation check
76726 */
76727
76728 if (!act->var_env) {
76729 DUK_ASSERT(act->lex_env == NULL);
76730 duk_js_init_activation_environment_records_delayed(thr, act);
76731 }
76732 DUK_ASSERT(act->lex_env != NULL);
76733 DUK_ASSERT(act->var_env != NULL);
76734
76735 env = act->var_env;
76736 DUK_ASSERT(env != NULL);
76737 DUK_ASSERT(DUK_HOBJECT_IS_ENV(env));
76738
76739 return duk__declvar_helper(thr, env, name, val, prop_flags, is_func_decl);
76740}
76741/*
76742 * Lexer for source files, ToNumber() string conversions, RegExp expressions,
76743 * and JSON.
76744 *
76745 * Provides a stream of Ecmascript tokens from an UTF-8/CESU-8 buffer. The
76746 * caller can also rewind the token stream into a certain position which is
76747 * needed by the compiler part for multi-pass scanning. Tokens are
76748 * represented as duk_token structures, and contain line number information.
76749 * Token types are identified with DUK_TOK_* defines.
76750 *
76751 * Characters are decoded into a fixed size lookup window consisting of
76752 * decoded Unicode code points, with window positions past the end of the
76753 * input filled with an invalid codepoint (-1). The tokenizer can thus
76754 * perform multiple character lookups efficiently and with few sanity
76755 * checks (such as access outside the end of the input), which keeps the
76756 * tokenization code small at the cost of performance.
76757 *
76758 * Character data in tokens, such as identifier names and string literals,
76759 * is encoded into CESU-8 format on-the-fly while parsing the token in
76760 * question. The string data is made reachable to garbage collection by
76761 * placing the token-related values in value stack entries allocated for
76762 * this purpose by the caller. The characters exist in Unicode code point
76763 * form only in the fixed size lookup window, which keeps character data
76764 * expansion (of especially ASCII data) low.
76765 *
76766 * Token parsing supports the full range of Unicode characters as described
76767 * in the E5 specification. Parsing has been optimized for ASCII characters
76768 * because ordinary Ecmascript code consists almost entirely of ASCII
76769 * characters. Matching of complex Unicode codepoint sets (such as in the
76770 * IdentifierStart and IdentifierPart productions) is optimized for size,
76771 * and is done using a linear scan of a bit-packed list of ranges. This is
76772 * very slow, but should never be entered unless the source code actually
76773 * contains Unicode characters.
76774 *
76775 * Ecmascript tokenization is partially context sensitive. First,
76776 * additional future reserved words are recognized in strict mode (see E5
76777 * Section 7.6.1.2). Second, a forward slash character ('/') can be
76778 * recognized either as starting a RegExp literal or as a division operator,
76779 * depending on context. The caller must provide necessary context flags
76780 * when requesting a new token.
76781 *
76782 * Future work:
76783 *
76784 * * Make line number tracking optional, as it consumes space.
76785 *
76786 * * Add a feature flag for disabling UTF-8 decoding of input, as most
76787 * source code is ASCII. Because of Unicode escapes written in ASCII,
76788 * this does not allow Unicode support to be removed from e.g.
76789 * duk_unicode_is_identifier_start() nor does it allow removal of CESU-8
76790 * encoding of e.g. string literals.
76791 *
76792 * * Add a feature flag for disabling Unicode compliance of e.g. identifier
76793 * names. This allows for a build more than a kilobyte smaller, because
76794 * Unicode ranges needed by duk_unicode_is_identifier_start() and
76795 * duk_unicode_is_identifier_part() can be dropped. String literals
76796 * should still be allowed to contain escaped Unicode, so this still does
76797 * not allow removal of CESU-8 encoding of e.g. string literals.
76798 *
76799 * * Character lookup tables for codepoints above BMP could be stripped.
76800 *
76801 * * Strictly speaking, E5 specification requires that source code consists
76802 * of 16-bit code units, and if not, must be conceptually converted to
76803 * that format first. The current lexer processes Unicode code points
76804 * and allows characters outside the BMP. These should be converted to
76805 * surrogate pairs while reading the source characters into the window,
76806 * not after tokens have been formed (as is done now). However, the fix
76807 * is not trivial because two characters are decoded from one codepoint.
76808 *
76809 * * Optimize for speed as well as size. Large if-else ladders are (at
76810 * least potentially) slow.
76811 */
76812
76813/* #include duk_internal.h -> already included */
76814
76815/*
76816 * Various defines and file specific helper macros
76817 */
76818
76819#define DUK__MAX_RE_DECESC_DIGITS 9
76820#define DUK__MAX_RE_QUANT_DIGITS 9 /* Does not allow e.g. 2**31-1, but one more would allow overflows of u32. */
76821
76822/* whether to use macros or helper function depends on call count */
76823#define DUK__ISDIGIT(x) ((x) >= DUK_ASC_0 && (x) <= DUK_ASC_9)
76824#define DUK__ISHEXDIGIT(x) duk__is_hex_digit((x))
76825#define DUK__ISOCTDIGIT(x) ((x) >= DUK_ASC_0 && (x) <= DUK_ASC_7)
76826#define DUK__ISDIGIT03(x) ((x) >= DUK_ASC_0 && (x) <= DUK_ASC_3)
76827#define DUK__ISDIGIT47(x) ((x) >= DUK_ASC_4 && (x) <= DUK_ASC_7)
76828
76829/* lexer character window helpers */
76830#define DUK__LOOKUP(lex_ctx,idx) ((lex_ctx)->window[(idx)].codepoint)
76831#define DUK__ADVANCECHARS(lex_ctx,count) duk__advance_chars((lex_ctx), (count))
76832#define DUK__ADVANCEBYTES(lex_ctx,count) duk__advance_bytes((lex_ctx), (count))
76833#define DUK__INITBUFFER(lex_ctx) duk__initbuffer((lex_ctx))
76834#define DUK__APPENDBUFFER(lex_ctx,x) duk__appendbuffer((lex_ctx), (duk_codepoint_t) (x))
76835#define DUK__APPENDBUFFER_ASCII(lex_ctx,x) duk__appendbuffer_ascii((lex_ctx), (duk_codepoint_t) (x))
76836
76837/* lookup shorthands (note: assume context variable is named 'lex_ctx') */
76838#define DUK__L0() DUK__LOOKUP(lex_ctx, 0)
76839#define DUK__L1() DUK__LOOKUP(lex_ctx, 1)
76840#define DUK__L2() DUK__LOOKUP(lex_ctx, 2)
76841#define DUK__L3() DUK__LOOKUP(lex_ctx, 3)
76842#define DUK__L4() DUK__LOOKUP(lex_ctx, 4)
76843#define DUK__L5() DUK__LOOKUP(lex_ctx, 5)
76844
76845/* packed advance/token number macro used by multiple functions */
76846#define DUK__ADVTOK(advbytes,tok) ((((advbytes) * sizeof(duk_lexer_codepoint)) << 8) + (tok))
76847
76848/*
76849 * Advance lookup window by N characters, filling in new characters as
76850 * necessary. After returning caller is guaranteed a character window of
76851 * at least DUK_LEXER_WINDOW_SIZE characters.
76852 *
76853 * The main function duk__advance_bytes() is called at least once per every
76854 * token so it has a major lexer/compiler performance impact. There are two
76855 * variants for the main duk__advance_bytes() algorithm: a sliding window
76856 * approach which is slightly faster at the cost of larger code footprint,
76857 * and a simple copying one.
76858 *
76859 * Decoding directly from the source string would be another lexing option.
76860 * But the lookup window based approach has the advantage of hiding the
76861 * source string and its encoding effectively which gives more flexibility
76862 * going forward to e.g. support chunked streaming of source from flash.
76863 *
76864 * Decodes UTF-8/CESU-8 leniently with support for code points from U+0000 to
76865 * U+10FFFF, causing an error if the input is unparseable. Leniency means:
76866 *
76867 * * Unicode code point validation is intentionally not performed,
76868 * except to check that the codepoint does not exceed 0x10ffff.
76869 *
76870 * * In particular, surrogate pairs are allowed and not combined, which
76871 * allows source files to represent all SourceCharacters with CESU-8.
76872 * Broken surrogate pairs are allowed, as Ecmascript does not mandate
76873 * their validation.
76874 *
76875 * * Allow non-shortest UTF-8 encodings.
76876 *
76877 * Leniency here causes few security concerns because all character data is
76878 * decoded into Unicode codepoints before lexer processing, and is then
76879 * re-encoded into CESU-8. The source can be parsed as strict UTF-8 with
76880 * a compiler option. However, Ecmascript source characters include -all-
76881 * 16-bit unsigned integer codepoints, so leniency seems to be appropriate.
76882 *
76883 * Note that codepoints above the BMP are not strictly SourceCharacters,
76884 * but the lexer still accepts them as such. Before ending up in a string
76885 * or an identifier name, codepoints above BMP are converted into surrogate
76886 * pairs and then CESU-8 encoded, resulting in 16-bit Unicode data as
76887 * expected by Ecmascript.
76888 *
76889 * An alternative approach to dealing with invalid or partial sequences
76890 * would be to skip them and replace them with e.g. the Unicode replacement
76891 * character U+FFFD. This has limited utility because a replacement character
76892 * will most likely cause a parse error, unless it occurs inside a string.
76893 * Further, Ecmascript source is typically pure ASCII.
76894 *
76895 * See:
76896 *
76897 * http://en.wikipedia.org/wiki/UTF-8
76898 * http://en.wikipedia.org/wiki/CESU-8
76899 * http://tools.ietf.org/html/rfc3629
76900 * http://en.wikipedia.org/wiki/UTF-8#Invalid_byte_sequences
76901 *
76902 * Future work:
76903 *
76904 * * Reject other invalid Unicode sequences (see Wikipedia entry for examples)
76905 * in strict UTF-8 mode.
76906 *
76907 * * Size optimize. An attempt to use a 16-byte lookup table for the first
76908 * byte resulted in a code increase though.
76909 *
76910 * * Is checking against maximum 0x10ffff really useful? 4-byte encoding
76911 * imposes a certain limit anyway.
76912 *
76913 * * Support chunked streaming of source code. Can be implemented either
76914 * by streaming chunks of bytes or chunks of codepoints.
76915 */
76916
76917#if defined(DUK_USE_LEXER_SLIDING_WINDOW)
76918DUK_LOCAL void duk__fill_lexer_buffer(duk_lexer_ctx *lex_ctx, duk_small_uint_t start_offset_bytes) {
76919 duk_lexer_codepoint *cp, *cp_end;
76920 duk_ucodepoint_t x;
76921 duk_small_uint_t contlen;
76922 const duk_uint8_t *p, *p_end;
76923#if defined(DUK_USE_STRICT_UTF8_SOURCE)
76924 duk_ucodepoint_t mincp;
76925#endif
76926 duk_int_t input_line;
76927
76928 /* Use temporaries and update lex_ctx only when finished. */
76929 input_line = lex_ctx->input_line;
76930 p = lex_ctx->input + lex_ctx->input_offset;
76931 p_end = lex_ctx->input + lex_ctx->input_length;
76932
76933 cp = (duk_lexer_codepoint *) (void *) ((duk_uint8_t *) lex_ctx->buffer + start_offset_bytes);
76934 cp_end = lex_ctx->buffer + DUK_LEXER_BUFFER_SIZE;
76935
76936 for (; cp != cp_end; cp++) {
76937 cp->offset = (duk_size_t) (p - lex_ctx->input);
76938 cp->line = input_line;
76939
76940 /* XXX: potential issue with signed pointers, p_end < p. */
76941 if (DUK_UNLIKELY(p >= p_end)) {
76942 /* If input_offset were assigned a negative value, it would
76943 * result in a large positive value. Most likely it would be
76944 * larger than input_length and be caught here. In any case
76945 * no memory unsafe behavior would happen.
76946 */
76947 cp->codepoint = -1;
76948 continue;
76949 }
76950
76951 x = (duk_ucodepoint_t) (*p++);
76952
76953 /* Fast path. */
76954
76955 if (DUK_LIKELY(x < 0x80UL)) {
76956 DUK_ASSERT(x != 0x2028UL && x != 0x2029UL); /* not LS/PS */
76957 if (DUK_UNLIKELY(x <= 0x000dUL)) {
76958 if ((x == 0x000aUL) ||
76959 ((x == 0x000dUL) && (p >= p_end || *p != 0x000aUL))) {
76960 /* lookup for 0x000a above assumes shortest encoding now */
76961
76962 /* E5 Section 7.3, treat the following as newlines:
76963 * LF
76964 * CR [not followed by LF]
76965 * LS
76966 * PS
76967 *
76968 * For CR LF, CR is ignored if it is followed by LF, and the LF will bump
76969 * the line number.
76970 */
76971 input_line++;
76972 }
76973 }
76974
76975 cp->codepoint = (duk_codepoint_t) x;
76976 continue;
76977 }
76978
76979 /* Slow path. */
76980
76981 if (x < 0xc0UL) {
76982 /* 10xx xxxx -> invalid */
76983 goto error_encoding;
76984 } else if (x < 0xe0UL) {
76985 /* 110x xxxx 10xx xxxx */
76986 contlen = 1;
76987#if defined(DUK_USE_STRICT_UTF8_SOURCE)
76988 mincp = 0x80UL;
76989#endif
76990 x = x & 0x1fUL;
76991 } else if (x < 0xf0UL) {
76992 /* 1110 xxxx 10xx xxxx 10xx xxxx */
76993 contlen = 2;
76994#if defined(DUK_USE_STRICT_UTF8_SOURCE)
76995 mincp = 0x800UL;
76996#endif
76997 x = x & 0x0fUL;
76998 } else if (x < 0xf8UL) {
76999 /* 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx */
77000 contlen = 3;
77001#if defined(DUK_USE_STRICT_UTF8_SOURCE)
77002 mincp = 0x10000UL;
77003#endif
77004 x = x & 0x07UL;
77005 } else {
77006 /* no point in supporting encodings of 5 or more bytes */
77007 goto error_encoding;
77008 }
77009
77010 DUK_ASSERT(p_end >= p);
77011 if ((duk_size_t) contlen > (duk_size_t) (p_end - p)) {
77012 goto error_clipped;
77013 }
77014
77015 while (contlen > 0) {
77016 duk_small_uint_t y;
77017 y = *p++;
77018 if ((y & 0xc0U) != 0x80U) {
77019 /* check that byte has the form 10xx xxxx */
77020 goto error_encoding;
77021 }
77022 x = x << 6;
77023 x += y & 0x3fUL;
77024 contlen--;
77025 }
77026
77027 /* check final character validity */
77028
77029 if (x > 0x10ffffUL) {
77030 goto error_encoding;
77031 }
77032#if defined(DUK_USE_STRICT_UTF8_SOURCE)
77033 if (x < mincp || (x >= 0xd800UL && x <= 0xdfffUL) || x == 0xfffeUL) {
77034 goto error_encoding;
77035 }
77036#endif
77037
77038 DUK_ASSERT(x != 0x000aUL && x != 0x000dUL);
77039 if ((x == 0x2028UL) || (x == 0x2029UL)) {
77040 input_line++;
77041 }
77042
77043 cp->codepoint = (duk_codepoint_t) x;
77044 }
77045
77046 lex_ctx->input_offset = (duk_size_t) (p - lex_ctx->input);
77047 lex_ctx->input_line = input_line;
77048 return;
77049
77050 error_clipped: /* clipped codepoint */
77051 error_encoding: /* invalid codepoint encoding or codepoint */
77052 lex_ctx->input_offset = (duk_size_t) (p - lex_ctx->input);
77053 lex_ctx->input_line = input_line;
77054
77055 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_DECODE_FAILED);
77056}
77057
77058DUK_LOCAL void duk__advance_bytes(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_bytes) {
77059 duk_small_uint_t used_bytes, avail_bytes;
77060
77061 DUK_ASSERT_DISABLE(count_bytes >= 0); /* unsigned */
77062 DUK_ASSERT(count_bytes <= (duk_small_uint_t) (DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint)));
77063 DUK_ASSERT(lex_ctx->window >= lex_ctx->buffer);
77064 DUK_ASSERT(lex_ctx->window < lex_ctx->buffer + DUK_LEXER_BUFFER_SIZE);
77065 DUK_ASSERT((duk_uint8_t *) lex_ctx->window + count_bytes <= (duk_uint8_t *) lex_ctx->buffer + DUK_LEXER_BUFFER_SIZE * sizeof(duk_lexer_codepoint));
77066
77067 /* Zero 'count' is also allowed to make call sites easier.
77068 * Arithmetic in bytes generates better code in GCC.
77069 */
77070
77071 lex_ctx->window = (duk_lexer_codepoint *) (void *) ((duk_uint8_t *) lex_ctx->window + count_bytes); /* avoid multiply */
77072 used_bytes = (duk_small_uint_t) ((duk_uint8_t *) lex_ctx->window - (duk_uint8_t *) lex_ctx->buffer);
77073 avail_bytes = DUK_LEXER_BUFFER_SIZE * sizeof(duk_lexer_codepoint) - used_bytes;
77074 if (avail_bytes < (duk_small_uint_t) (DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint))) {
77075 /* Not enough data to provide a full window, so "scroll" window to
77076 * start of buffer and fill up the rest.
77077 */
77078 DUK_MEMMOVE((void *) lex_ctx->buffer,
77079 (const void *) lex_ctx->window,
77080 (size_t) avail_bytes);
77081 lex_ctx->window = lex_ctx->buffer;
77082 duk__fill_lexer_buffer(lex_ctx, avail_bytes);
77083 }
77084}
77085
77086DUK_LOCAL void duk__init_lexer_window(duk_lexer_ctx *lex_ctx) {
77087 lex_ctx->window = lex_ctx->buffer;
77088 duk__fill_lexer_buffer(lex_ctx, 0);
77089}
77090#else /* DUK_USE_LEXER_SLIDING_WINDOW */
77091DUK_LOCAL duk_codepoint_t duk__read_char(duk_lexer_ctx *lex_ctx) {
77092 duk_ucodepoint_t x;
77093 duk_small_uint_t len;
77094 duk_small_uint_t i;
77095 const duk_uint8_t *p;
77096#if defined(DUK_USE_STRICT_UTF8_SOURCE)
77097 duk_ucodepoint_t mincp;
77098#endif
77099 duk_size_t input_offset;
77100
77101 input_offset = lex_ctx->input_offset;
77102 if (DUK_UNLIKELY(input_offset >= lex_ctx->input_length)) {
77103 /* If input_offset were assigned a negative value, it would
77104 * result in a large positive value. Most likely it would be
77105 * larger than input_length and be caught here. In any case
77106 * no memory unsafe behavior would happen.
77107 */
77108 return -1;
77109 }
77110
77111 p = lex_ctx->input + input_offset;
77112 x = (duk_ucodepoint_t) (*p);
77113
77114 if (DUK_LIKELY(x < 0x80UL)) {
77115 /* 0xxx xxxx -> fast path */
77116
77117 /* input offset tracking */
77118 lex_ctx->input_offset++;
77119
77120 DUK_ASSERT(x != 0x2028UL && x != 0x2029UL); /* not LS/PS */
77121 if (DUK_UNLIKELY(x <= 0x000dUL)) {
77122 if ((x == 0x000aUL) ||
77123 ((x == 0x000dUL) && (lex_ctx->input_offset >= lex_ctx->input_length ||
77124 lex_ctx->input[lex_ctx->input_offset] != 0x000aUL))) {
77125 /* lookup for 0x000a above assumes shortest encoding now */
77126
77127 /* E5 Section 7.3, treat the following as newlines:
77128 * LF
77129 * CR [not followed by LF]
77130 * LS
77131 * PS
77132 *
77133 * For CR LF, CR is ignored if it is followed by LF, and the LF will bump
77134 * the line number.
77135 */
77136 lex_ctx->input_line++;
77137 }
77138 }
77139
77140 return (duk_codepoint_t) x;
77141 }
77142
77143 /* Slow path. */
77144
77145 if (x < 0xc0UL) {
77146 /* 10xx xxxx -> invalid */
77147 goto error_encoding;
77148 } else if (x < 0xe0UL) {
77149 /* 110x xxxx 10xx xxxx */
77150 len = 2;
77151#if defined(DUK_USE_STRICT_UTF8_SOURCE)
77152 mincp = 0x80UL;
77153#endif
77154 x = x & 0x1fUL;
77155 } else if (x < 0xf0UL) {
77156 /* 1110 xxxx 10xx xxxx 10xx xxxx */
77157 len = 3;
77158#if defined(DUK_USE_STRICT_UTF8_SOURCE)
77159 mincp = 0x800UL;
77160#endif
77161 x = x & 0x0fUL;
77162 } else if (x < 0xf8UL) {
77163 /* 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx */
77164 len = 4;
77165#if defined(DUK_USE_STRICT_UTF8_SOURCE)
77166 mincp = 0x10000UL;
77167#endif
77168 x = x & 0x07UL;
77169 } else {
77170 /* no point in supporting encodings of 5 or more bytes */
77171 goto error_encoding;
77172 }
77173
77174 DUK_ASSERT(lex_ctx->input_length >= lex_ctx->input_offset);
77175 if ((duk_size_t) len > (duk_size_t) (lex_ctx->input_length - lex_ctx->input_offset)) {
77176 goto error_clipped;
77177 }
77178
77179 p++;
77180 for (i = 1; i < len; i++) {
77181 duk_small_uint_t y;
77182 y = *p++;
77183 if ((y & 0xc0U) != 0x80U) {
77184 /* check that byte has the form 10xx xxxx */
77185 goto error_encoding;
77186 }
77187 x = x << 6;
77188 x += y & 0x3fUL;
77189 }
77190
77191 /* check final character validity */
77192
77193 if (x > 0x10ffffUL) {
77194 goto error_encoding;
77195 }
77196#if defined(DUK_USE_STRICT_UTF8_SOURCE)
77197 if (x < mincp || (x >= 0xd800UL && x <= 0xdfffUL) || x == 0xfffeUL) {
77198 goto error_encoding;
77199 }
77200#endif
77201
77202 /* input offset tracking */
77203 lex_ctx->input_offset += len;
77204
77205 /* line tracking */
77206 DUK_ASSERT(x != 0x000aUL && x != 0x000dUL);
77207 if ((x == 0x2028UL) || (x == 0x2029UL)) {
77208 lex_ctx->input_line++;
77209 }
77210
77211 return (duk_codepoint_t) x;
77212
77213 error_clipped: /* clipped codepoint */
77214 error_encoding: /* invalid codepoint encoding or codepoint */
77215 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_DECODE_FAILED);
77216 return 0;
77217}
77218
77219DUK_LOCAL void duk__advance_bytes(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_bytes) {
77220 duk_small_uint_t keep_bytes;
77221 duk_lexer_codepoint *cp, *cp_end;
77222
77223 DUK_ASSERT_DISABLE(count_bytes >= 0); /* unsigned */
77224 DUK_ASSERT(count_bytes <= (duk_small_uint_t) (DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint)));
77225
77226 /* Zero 'count' is also allowed to make call sites easier. */
77227
77228 keep_bytes = DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint) - count_bytes;
77229 DUK_MEMMOVE((void *) lex_ctx->window,
77230 (const void *) ((duk_uint8_t *) lex_ctx->window + count_bytes),
77231 (size_t) keep_bytes);
77232
77233 cp = (duk_lexer_codepoint *) ((duk_uint8_t *) lex_ctx->window + keep_bytes);
77234 cp_end = lex_ctx->window + DUK_LEXER_WINDOW_SIZE;
77235 for (; cp != cp_end; cp++) {
77236 cp->offset = lex_ctx->input_offset;
77237 cp->line = lex_ctx->input_line;
77238 cp->codepoint = duk__read_char(lex_ctx);
77239 }
77240}
77241
77242DUK_LOCAL void duk__init_lexer_window(duk_lexer_ctx *lex_ctx) {
77243 /* Call with count == DUK_LEXER_WINDOW_SIZE to fill buffer initially. */
77244 duk__advance_bytes(lex_ctx, DUK_LEXER_WINDOW_SIZE * sizeof(duk_lexer_codepoint)); /* fill window */
77245}
77246#endif /* DUK_USE_LEXER_SLIDING_WINDOW */
77247
77248DUK_LOCAL void duk__advance_chars(duk_lexer_ctx *lex_ctx, duk_small_uint_t count_chars) {
77249 duk__advance_bytes(lex_ctx, count_chars * sizeof(duk_lexer_codepoint));
77250}
77251
77252/*
77253 * (Re)initialize the temporary byte buffer. May be called extra times
77254 * with little impact.
77255 */
77256
77257DUK_LOCAL void duk__initbuffer(duk_lexer_ctx *lex_ctx) {
77258 /* Reuse buffer as is unless buffer has grown large. */
77259 if (DUK_HBUFFER_DYNAMIC_GET_SIZE(lex_ctx->buf) < DUK_LEXER_TEMP_BUF_LIMIT) {
77260 /* Keep current size */
77261 } else {
77262 duk_hbuffer_resize(lex_ctx->thr, lex_ctx->buf, DUK_LEXER_TEMP_BUF_LIMIT);
77263 }
77264
77265 DUK_BW_INIT_WITHBUF(lex_ctx->thr, &lex_ctx->bw, lex_ctx->buf);
77266}
77267
77268/*
77269 * Append a Unicode codepoint to the temporary byte buffer. Performs
77270 * CESU-8 surrogate pair encoding for codepoints above the BMP.
77271 * Existing surrogate pairs are allowed and also encoded into CESU-8.
77272 */
77273
77274DUK_LOCAL void duk__appendbuffer(duk_lexer_ctx *lex_ctx, duk_codepoint_t x) {
77275 /*
77276 * Since character data is only generated by decoding the source or by
77277 * the compiler itself, we rely on the input codepoints being correct
77278 * and avoid a check here.
77279 *
77280 * Character data can also come here through decoding of Unicode
77281 * escapes ("\udead\ubeef") so all 16-but unsigned values can be
77282 * present, even when the source file itself is strict UTF-8.
77283 */
77284 DUK_ASSERT(x >= 0 && x <= 0x10ffffL);
77285
77286 DUK_BW_WRITE_ENSURE_CESU8(lex_ctx->thr, &lex_ctx->bw, (duk_ucodepoint_t) x);
77287}
77288
77289DUK_LOCAL void duk__appendbuffer_ascii(duk_lexer_ctx *lex_ctx, duk_codepoint_t x) {
77290 /* ASCII characters can be emitted as a single byte without encoding
77291 * which matters for some fast paths.
77292 */
77293 DUK_ASSERT(x >= 0 && x <= 0x7f);
77294
77295 DUK_BW_WRITE_ENSURE_U8(lex_ctx->thr, &lex_ctx->bw, (duk_uint8_t) x);
77296}
77297
77298/*
77299 * Intern the temporary byte buffer into a valstack slot
77300 * (in practice, slot1 or slot2).
77301 */
77302
77303DUK_LOCAL duk_hstring *duk__internbuffer(duk_lexer_ctx *lex_ctx, duk_idx_t valstack_idx) {
77304 duk_context *ctx = (duk_context *) lex_ctx->thr;
77305
77306 DUK_ASSERT(valstack_idx == lex_ctx->slot1_idx || valstack_idx == lex_ctx->slot2_idx);
77307
77308 DUK_BW_PUSH_AS_STRING(lex_ctx->thr, &lex_ctx->bw);
77309 duk_replace(ctx, valstack_idx);
77310 return duk_known_hstring(ctx, valstack_idx);
77311}
77312
77313/*
77314 * Init lexer context
77315 */
77316
77317DUK_INTERNAL void duk_lexer_initctx(duk_lexer_ctx *lex_ctx) {
77318 DUK_ASSERT(lex_ctx != NULL);
77319
77320 DUK_MEMZERO(lex_ctx, sizeof(*lex_ctx));
77321#if defined(DUK_USE_EXPLICIT_NULL_INIT)
77322#if defined(DUK_USE_LEXER_SLIDING_WINDOW)
77323 lex_ctx->window = NULL;
77324#endif
77325 lex_ctx->thr = NULL;
77326 lex_ctx->input = NULL;
77327 lex_ctx->buf = NULL;
77328#endif
77329}
77330
77331/*
77332 * Set lexer input position and reinitialize lookup window.
77333 */
77334
77335DUK_INTERNAL void duk_lexer_getpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt) {
77336 pt->offset = lex_ctx->window[0].offset;
77337 pt->line = lex_ctx->window[0].line;
77338}
77339
77340DUK_INTERNAL void duk_lexer_setpoint(duk_lexer_ctx *lex_ctx, duk_lexer_point *pt) {
77341 DUK_ASSERT_DISABLE(pt->offset >= 0); /* unsigned */
77342 DUK_ASSERT(pt->line >= 1);
77343 lex_ctx->input_offset = pt->offset;
77344 lex_ctx->input_line = pt->line;
77345 duk__init_lexer_window(lex_ctx);
77346}
77347
77348/*
77349 * Lexing helpers
77350 */
77351
77352/* Numeric value of a hex digit (also covers octal and decimal digits) or
77353 * -1 if not a valid hex digit.
77354 */
77355DUK_LOCAL duk_codepoint_t duk__hexval_validate(duk_codepoint_t x) {
77356 duk_small_int_t t;
77357
77358 /* Here 'x' is a Unicode codepoint */
77359 if (DUK_LIKELY(x >= 0 && x <= 0xff)) {
77360 t = duk_hex_dectab[x];
77361 if (DUK_LIKELY(t >= 0)) {
77362 return t;
77363 }
77364 }
77365
77366 return -1;
77367}
77368
77369/* Just a wrapper for call sites where 'x' is known to be valid so
77370 * we assert for it before decoding.
77371 */
77372DUK_LOCAL duk_codepoint_t duk__hexval(duk_codepoint_t x) {
77373 duk_codepoint_t ret;
77374
77375 DUK_ASSERT((x >= DUK_ASC_0 && x <= DUK_ASC_9) ||
77376 (x >= DUK_ASC_LC_A && x <= DUK_ASC_LC_F) ||
77377 (x >= DUK_ASC_UC_A && x <= DUK_ASC_UC_F));
77378 ret = duk__hexval_validate(x);
77379 DUK_ASSERT(ret >= 0 && ret <= 15);
77380 return ret;
77381}
77382
77383/* having this as a separate function provided a size benefit */
77384DUK_LOCAL duk_bool_t duk__is_hex_digit(duk_codepoint_t x) {
77385 if (DUK_LIKELY(x >= 0 && x <= 0xff)) {
77386 return (duk_hex_dectab[x] >= 0);
77387 }
77388 return 0;
77389}
77390
77391/* Parse a Unicode escape of the form \xHH, \uHHHH, or \u{H+}. Shared by
77392 * source and RegExp parsing.
77393 */
77394DUK_LOCAL duk_codepoint_t duk__lexer_parse_escape(duk_lexer_ctx *lex_ctx, duk_bool_t allow_es6) {
77395 duk_small_int_t digits; /* Initial value 2 or 4 for fixed length escapes, 0 for ES2015 \u{H+}. */
77396 duk_codepoint_t escval;
77397 duk_codepoint_t x;
77398 duk_small_int_t adv;
77399
77400 DUK_ASSERT(DUK__L0() == DUK_ASC_BACKSLASH); /* caller responsibilities */
77401 DUK_ASSERT(DUK__L1() == DUK_ASC_LC_X || DUK__L1() == DUK_ASC_LC_U);
77402 DUK_UNREF(allow_es6);
77403
77404 adv = 2;
77405 digits = 2;
77406 if (DUK__L1() == DUK_ASC_LC_U) {
77407 digits = 4;
77408#if defined(DUK_USE_ES6_UNICODE_ESCAPE)
77409 if (DUK__L2() == DUK_ASC_LCURLY && allow_es6) {
77410 digits = 0;
77411 adv = 3;
77412 }
77413#endif
77414 }
77415 DUK__ADVANCECHARS(lex_ctx, adv);
77416
77417 escval = 0;
77418 for (;;) {
77419 /* One of the escape forms: \xHH, \uHHHH, \u{H+}.
77420 * The 'digits' variable tracks parsing state and is
77421 * initialized to:
77422 *
77423 * \xHH 2
77424 * \uHH 4
77425 * \u{H+} 0 first time, updated to -1 to indicate
77426 * at least one digit has been parsed
77427 *
77428 * Octal parsing is handled separately because it can be
77429 * done with fixed lookahead and also has validation
77430 * rules which depend on the escape length (which is
77431 * variable).
77432 *
77433 * We don't need a specific check for x < 0 (end of
77434 * input) or duk_unicode_is_line_terminator(x)
77435 * because the 'dig' decode will fail and lead to a
77436 * SyntaxError.
77437 */
77438 duk_codepoint_t dig;
77439
77440 x = DUK__L0();
77441 DUK__ADVANCECHARS(lex_ctx, 1);
77442
77443 dig = duk__hexval_validate(x);
77444 if (digits > 0) {
77445 digits--;
77446 if (dig < 0) {
77447 goto fail_escape;
77448 }
77449 DUK_ASSERT(dig >= 0x00 && dig <= 0x0f);
77450 escval = (escval << 4) + dig;
77451 if (digits == 0) {
77452 DUK_ASSERT(escval >= 0 && escval <= 0xffffL);
77453 break;
77454 }
77455 } else {
77456#if defined(DUK_USE_ES6_UNICODE_ESCAPE)
77457 DUK_ASSERT(digits == 0 /* first time */ || digits == -1 /* others */);
77458 if (dig >= 0) {
77459 DUK_ASSERT(dig >= 0x00 && dig <= 0x0f);
77460 escval = (escval << 4) + dig;
77461 if (escval > 0x10ffffL) {
77462 goto fail_escape;
77463 }
77464 } else if (x == DUK_ASC_RCURLY) {
77465 if (digits == 0) {
77466 /* Empty escape, \u{}. */
77467 goto fail_escape;
77468 }
77469 DUK_ASSERT(escval >= 0 && escval <= 0x10ffffL);
77470 break;
77471 } else {
77472 goto fail_escape;
77473 }
77474 digits = -1; /* Indicate we have at least one digit. */
77475#else /* DUK_USE_ES6_UNICODE_ESCAPE */
77476 DUK_ASSERT(0); /* Never happens if \u{H+} support disabled. */
77477#endif /* DUK_USE_ES6_UNICODE_ESCAPE */
77478 }
77479 }
77480
77481 return escval;
77482
77483 fail_escape:
77484 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_ESCAPE);
77485}
77486
77487/* XXX: move strict mode to lex_ctx? */
77488DUK_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) {
77489 duk_small_int_t adv;
77490
77491 for (adv = 1 /* initial quote */ ;;) {
77492 duk_codepoint_t x;
77493
77494 DUK__ADVANCECHARS(lex_ctx, adv); /* eat opening quote on first loop */
77495 x = DUK__L0();
77496
77497 adv = 1;
77498 if (x == quote) {
77499 DUK__ADVANCECHARS(lex_ctx, 1); /* eat closing quote */
77500 break;
77501 } else if (x == '\\') {
77502 /* DUK__L0 -> '\' char
77503 * DUK__L1 ... DUK__L5 -> more lookup
77504 */
77505 duk_small_int_t emitcp = -1;
77506
77507 x = DUK__L1();
77508
77509 /* How much to advance before next loop. */
77510 adv = 2; /* note: long live range */
77511
77512 switch (x) {
77513 case '\'':
77514 emitcp = 0x0027;
77515 break;
77516 case '"':
77517 emitcp = 0x0022;
77518 break;
77519 case '\\':
77520 emitcp = 0x005c;
77521 break;
77522 case 'b':
77523 emitcp = 0x0008;
77524 break;
77525 case 'f':
77526 emitcp = 0x000c;
77527 break;
77528 case 'n':
77529 emitcp = 0x000a;
77530 break;
77531 case 'r':
77532 emitcp = 0x000d;
77533 break;
77534 case 't':
77535 emitcp = 0x0009;
77536 break;
77537 case 'v':
77538 emitcp = 0x000b;
77539 break;
77540 case 'x':
77541 case 'u': {
77542 duk_codepoint_t esc_cp;
77543 esc_cp = duk__lexer_parse_escape(lex_ctx, 1 /*allow_es6*/);
77544 DUK__APPENDBUFFER(lex_ctx, esc_cp);
77545 adv = 0;
77546 break;
77547 }
77548 default: {
77549 if (duk_unicode_is_line_terminator(x)) {
77550 /* line continuation */
77551 if (x == 0x000d && DUK__L2() == 0x000a) {
77552 /* CR LF again a special case */
77553 adv = 3; /* line terminator, CR, LF */
77554 }
77555 } else if (DUK__ISDIGIT(x)) {
77556 /*
77557 * Octal escape or zero escape:
77558 * \0 (lookahead not OctalDigit)
77559 * \1 ... \7 (lookahead not OctalDigit)
77560 * \ZeroToThree OctalDigit (lookahead not OctalDigit)
77561 * \FourToSeven OctalDigit (no lookahead restrictions)
77562 * \ZeroToThree OctalDigit OctalDigit (no lookahead restrictions)
77563 *
77564 * Zero escape is part of the standard syntax. Octal escapes are
77565 * defined in E5 Section B.1.2, and are only allowed in non-strict mode.
77566 * Any other productions starting with a decimal digit are invalid
77567 * but are in practice treated like identity escapes.
77568 *
77569 * Parse octal (up to 3 digits) from the lookup window.
77570 */
77571
77572 duk_codepoint_t tmp;
77573 duk_small_uint_t lookup_idx;
77574
77575 emitcp = 0;
77576 for (lookup_idx = 1; lookup_idx <= 3; lookup_idx++) {
77577 DUK_DDD(DUK_DDDPRINT("lookup_idx=%ld, emitcp=%ld", (long) lookup_idx, (long) emitcp));
77578 tmp = DUK__LOOKUP(lex_ctx, lookup_idx);
77579 if (tmp < DUK_ASC_0 || tmp > DUK_ASC_7) {
77580 /* No more valid digits. */
77581 break;
77582 }
77583 tmp = (emitcp << 3) + (tmp - DUK_ASC_0);
77584 if (tmp > 0xff) {
77585 /* Three digit octal escapes above \377 (= 0xff)
77586 * are not allowed.
77587 */
77588 break;
77589 }
77590 emitcp = tmp;
77591 }
77592 DUK_DDD(DUK_DDDPRINT("final lookup_idx=%ld, emitcp=%ld", (long) lookup_idx, (long) emitcp));
77593
77594 adv = lookup_idx;
77595 if (lookup_idx == 1) {
77596 /* \8 or \9 -> treat as literal, accept also
77597 * in strict mode.
77598 */
77599 DUK_DDD(DUK_DDDPRINT("\\8 or \\9 -> treat as literal, accept in strict mode too"));
77600 emitcp = x;
77601 adv++; /* correction to above, eat offending character */
77602 } else if (lookup_idx == 2 && emitcp == 0) {
77603 /* Zero escape, also allowed in non-strict mode. */
77604 DUK_DDD(DUK_DDDPRINT("\\0 -> accept in strict mode too"));
77605 } else {
77606 /* Valid octal, only accept in non-strict mode. */
77607 DUK_DDD(DUK_DDDPRINT("octal literal %ld -> accept only in non-strict-mode", (long) emitcp));
77608 DUK_ASSERT(emitcp >= 0 && emitcp <= 0xff);
77609 if (strict_mode) {
77610 goto fail_escape;
77611 }
77612 }
77613 } else if (x < 0) {
77614 goto fail_unterminated;
77615 } else {
77616 /* escaped NonEscapeCharacter */
77617 DUK__APPENDBUFFER(lex_ctx, x);
77618 }
77619 } /* end default clause */
77620 } /* end switch */
77621
77622 /* Shared handling for single codepoint escapes. */
77623 if (emitcp >= 0) {
77624 DUK__APPENDBUFFER(lex_ctx, emitcp);
77625 }
77626
77627 /* Track number of escapes; count not really needed but directive
77628 * prologues need to detect whether there were any escapes or line
77629 * continuations or not.
77630 */
77631 out_token->num_escapes++;
77632 } else if (x >= 0x20 && x <= 0x7f) {
77633 /* Fast path for ASCII case, avoids line terminator
77634 * check and CESU-8 encoding.
77635 */
77636 DUK_ASSERT(x >= 0);
77637 DUK_ASSERT(!duk_unicode_is_line_terminator(x));
77638 DUK_ASSERT(x != quote);
77639 DUK_ASSERT(x != DUK_ASC_BACKSLASH);
77640 DUK__APPENDBUFFER_ASCII(lex_ctx, x);
77641 } else if (x < 0 || duk_unicode_is_line_terminator(x)) {
77642 goto fail_unterminated;
77643 } else {
77644 /* Character which is part of the string but wasn't handled
77645 * by the fast path.
77646 */
77647 DUK__APPENDBUFFER(lex_ctx, x);
77648 }
77649 } /* string parse loop */
77650
77651 return;
77652
77653 fail_escape:
77654 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_ESCAPE);
77655 return;
77656
77657 fail_unterminated:
77658 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_STRING);
77659 return;
77660}
77661
77662/*
77663 * Parse Ecmascript source InputElementDiv or InputElementRegExp
77664 * (E5 Section 7), skipping whitespace, comments, and line terminators.
77665 *
77666 * Possible results are:
77667 * (1) a token
77668 * (2) a line terminator (skipped)
77669 * (3) a comment (skipped)
77670 * (4) EOF
77671 *
77672 * White space is automatically skipped from the current position (but
77673 * not after the input element). If input has already ended, returns
77674 * DUK_TOK_EOF indefinitely. If a parse error occurs, uses an DUK_ERROR()
77675 * macro call (and hence a longjmp through current heap longjmp context).
77676 * Comments and line terminator tokens are automatically skipped.
77677 *
77678 * The input element being matched is determined by regexp_mode; if set,
77679 * parses a InputElementRegExp, otherwise a InputElementDiv. The
77680 * difference between these are handling of productions starting with a
77681 * forward slash.
77682 *
77683 * If strict_mode is set, recognizes additional future reserved words
77684 * specific to strict mode, and refuses to parse octal literals.
77685 *
77686 * The matching strategy below is to (currently) use a six character
77687 * lookup window to quickly determine which production is the -longest-
77688 * matching one, and then parse that. The top-level if-else clauses
77689 * match the first character, and the code blocks for each clause
77690 * handle -all- alternatives for that first character. Ecmascript
77691 * specification uses the "longest match wins" semantics, so the order
77692 * of the if-clauses matters.
77693 *
77694 * Misc notes:
77695 *
77696 * * Ecmascript numeric literals do not accept a sign character.
77697 * Consequently e.g. "-1.0" is parsed as two tokens: a negative
77698 * sign and a positive numeric literal. The compiler performs
77699 * the negation during compilation, so this has no adverse impact.
77700 *
77701 * * There is no token for "undefined": it is just a value available
77702 * from the global object (or simply established by doing a reference
77703 * to an undefined value).
77704 *
77705 * * Some contexts want Identifier tokens, which are IdentifierNames
77706 * excluding reserved words, while some contexts want IdentifierNames
77707 * directly. In the latter case e.g. "while" is interpreted as an
77708 * identifier name, not a DUK_TOK_WHILE token. The solution here is
77709 * to provide both token types: DUK_TOK_WHILE goes to 't' while
77710 * DUK_TOK_IDENTIFIER goes to 't_nores', and 'slot1' always contains
77711 * the identifier / keyword name.
77712 *
77713 * * Directive prologue needs to identify string literals such as
77714 * "use strict" and 'use strict', which are sensitive to line
77715 * continuations and escape sequences. For instance, "use\u0020strict"
77716 * is a valid directive but is distinct from "use strict". The solution
77717 * here is to decode escapes while tokenizing, but to keep track of the
77718 * number of escapes. Directive detection can then check that the
77719 * number of escapes is zero.
77720 *
77721 * * Multi-line comments with one or more internal LineTerminator are
77722 * treated like a line terminator to comply with automatic semicolon
77723 * insertion.
77724 */
77725
77726DUK_INTERNAL
77727void duk_lexer_parse_js_input_element(duk_lexer_ctx *lex_ctx,
77728 duk_token *out_token,
77729 duk_bool_t strict_mode,
77730 duk_bool_t regexp_mode) {
77731 duk_codepoint_t x; /* temporary, must be signed and 32-bit to hold Unicode code points */
77732 duk_small_uint_t advtok = 0; /* (advance << 8) + token_type, updated at function end,
77733 * init is unnecessary but suppresses "may be used uninitialized" warnings.
77734 */
77735 duk_bool_t got_lineterm = 0; /* got lineterm preceding non-whitespace, non-lineterm token */
77736
77737 if (++lex_ctx->token_count >= lex_ctx->token_limit) {
77738 goto fail_token_limit;
77739 }
77740
77741 out_token->t = DUK_TOK_EOF;
77742 out_token->t_nores = -1; /* marker: copy t if not changed */
77743#if 0 /* not necessary to init, disabled for faster parsing */
77744 out_token->num = DUK_DOUBLE_NAN;
77745 out_token->str1 = NULL;
77746 out_token->str2 = NULL;
77747#endif
77748 out_token->num_escapes = 0;
77749 /* out_token->lineterm set by caller */
77750
77751 /* This would be nice, but parsing is faster without resetting the
77752 * value slots. The only side effect is that references to temporary
77753 * string values may linger until lexing is finished; they're then
77754 * freed normally.
77755 */
77756#if 0
77757 duk_to_undefined((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
77758 duk_to_undefined((duk_context *) lex_ctx->thr, lex_ctx->slot2_idx);
77759#endif
77760
77761 /* 'advtok' indicates how much to advance and which token id to assign
77762 * at the end. This shared functionality minimizes code size. All
77763 * code paths are required to set 'advtok' to some value, so no default
77764 * init value is used. Code paths calling DUK_ERROR() never return so
77765 * they don't need to set advtok.
77766 */
77767
77768 /*
77769 * Matching order:
77770 *
77771 * Punctuator first chars, also covers comments, regexps
77772 * LineTerminator
77773 * Identifier or reserved word, also covers null/true/false literals
77774 * NumericLiteral
77775 * StringLiteral
77776 * EOF
77777 *
77778 * The order does not matter as long as the longest match is
77779 * always correctly identified. There are order dependencies
77780 * in the clauses, so it's not trivial to convert to a switch.
77781 */
77782
77783 restart_lineupdate:
77784 out_token->start_line = lex_ctx->window[0].line;
77785
77786 restart:
77787 out_token->start_offset = lex_ctx->window[0].offset;
77788
77789 x = DUK__L0();
77790
77791 switch (x) {
77792 case DUK_ASC_SPACE:
77793 case DUK_ASC_HT: /* fast paths for space and tab */
77794 DUK__ADVANCECHARS(lex_ctx, 1);
77795 goto restart;
77796 case DUK_ASC_LF: /* LF line terminator; CR LF and Unicode lineterms are handled in slow path */
77797 DUK__ADVANCECHARS(lex_ctx, 1);
77798 got_lineterm = 1;
77799 goto restart_lineupdate;
77800 case DUK_ASC_SLASH: /* '/' */
77801 if (DUK__L1() == DUK_ASC_SLASH) {
77802 /*
77803 * E5 Section 7.4, allow SourceCharacter (which is any 16-bit
77804 * code point).
77805 */
77806
77807 /* DUK__ADVANCECHARS(lex_ctx, 2) would be correct here, but it unnecessary */
77808 for (;;) {
77809 x = DUK__L0();
77810 if (x < 0 || duk_unicode_is_line_terminator(x)) {
77811 break;
77812 }
77813 DUK__ADVANCECHARS(lex_ctx, 1);
77814 }
77815 goto restart; /* line terminator will be handled on next round */
77816 } else if (DUK__L1() == DUK_ASC_STAR) {
77817 /*
77818 * E5 Section 7.4. If the multi-line comment contains a newline,
77819 * it is treated like a single line terminator for automatic
77820 * semicolon insertion.
77821 */
77822
77823 duk_bool_t last_asterisk = 0;
77824 DUK__ADVANCECHARS(lex_ctx, 2);
77825 for (;;) {
77826 x = DUK__L0();
77827 if (x < 0) {
77828 goto fail_unterm_comment;
77829 }
77830 DUK__ADVANCECHARS(lex_ctx, 1);
77831 if (last_asterisk && x == DUK_ASC_SLASH) {
77832 break;
77833 }
77834 if (duk_unicode_is_line_terminator(x)) {
77835 got_lineterm = 1;
77836 }
77837 last_asterisk = (x == DUK_ASC_STAR);
77838 }
77839 goto restart_lineupdate;
77840 } else if (regexp_mode) {
77841#if defined(DUK_USE_REGEXP_SUPPORT)
77842 /*
77843 * "/" followed by something in regexp mode. See E5 Section 7.8.5.
77844 *
77845 * RegExp parsing is a bit complex. First, the regexp body is delimited
77846 * by forward slashes, but the body may also contain forward slashes as
77847 * part of an escape sequence or inside a character class (delimited by
77848 * square brackets). A mini state machine is used to implement these.
77849 *
77850 * Further, an early (parse time) error must be thrown if the regexp
77851 * would cause a run-time error when used in the expression new RegExp(...).
77852 * Parsing here simply extracts the (candidate) regexp, and also accepts
77853 * invalid regular expressions (which are delimited properly). The caller
77854 * (compiler) must perform final validation and regexp compilation.
77855 *
77856 * RegExp first char may not be '/' (single line comment) or '*' (multi-
77857 * line comment). These have already been checked above, so there is no
77858 * need below for special handling of the first regexp character as in
77859 * the E5 productions.
77860 *
77861 * About unicode escapes within regexp literals:
77862 *
77863 * E5 Section 7.8.5 grammar does NOT accept \uHHHH escapes.
77864 * However, Section 6 states that regexps accept the escapes,
77865 * see paragraph starting with "In string literals...".
77866 * The regexp grammar, which sees the decoded regexp literal
77867 * (after lexical parsing) DOES have a \uHHHH unicode escape.
77868 * So, for instance:
77869 *
77870 * /\u1234/
77871 *
77872 * should first be parsed by the lexical grammar as:
77873 *
77874 * '\' 'u' RegularExpressionBackslashSequence
77875 * '1' RegularExpressionNonTerminator
77876 * '2' RegularExpressionNonTerminator
77877 * '3' RegularExpressionNonTerminator
77878 * '4' RegularExpressionNonTerminator
77879 *
77880 * and the escape itself is then parsed by the regexp engine.
77881 * This is the current implementation.
77882 *
77883 * Minor spec inconsistency:
77884 *
77885 * E5 Section 7.8.5 RegularExpressionBackslashSequence is:
77886 *
77887 * \ RegularExpressionNonTerminator
77888 *
77889 * while Section A.1 RegularExpressionBackslashSequence is:
77890 *
77891 * \ NonTerminator
77892 *
77893 * The latter is not normative and a typo.
77894 *
77895 */
77896
77897 /* first, parse regexp body roughly */
77898
77899 duk_small_int_t state = 0; /* 0=base, 1=esc, 2=class, 3=class+esc */
77900
77901 DUK__INITBUFFER(lex_ctx);
77902 for (;;) {
77903 DUK__ADVANCECHARS(lex_ctx, 1); /* skip opening slash on first loop */
77904 x = DUK__L0();
77905 if (x < 0 || duk_unicode_is_line_terminator(x)) {
77906 goto fail_unterm_regexp;
77907 }
77908 x = DUK__L0(); /* re-read to avoid spill / fetch */
77909 if (state == 0) {
77910 if (x == DUK_ASC_SLASH) {
77911 DUK__ADVANCECHARS(lex_ctx, 1); /* eat closing slash */
77912 break;
77913 } else if (x == DUK_ASC_BACKSLASH) {
77914 state = 1;
77915 } else if (x == DUK_ASC_LBRACKET) {
77916 state = 2;
77917 }
77918 } else if (state == 1) {
77919 state = 0;
77920 } else if (state == 2) {
77921 if (x == DUK_ASC_RBRACKET) {
77922 state = 0;
77923 } else if (x == DUK_ASC_BACKSLASH) {
77924 state = 3;
77925 }
77926 } else { /* state == 3 */
77927 state = 2;
77928 }
77929 DUK__APPENDBUFFER(lex_ctx, x);
77930 }
77931 out_token->str1 = duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
77932
77933 /* second, parse flags */
77934
77935 DUK__INITBUFFER(lex_ctx);
77936 for (;;) {
77937 x = DUK__L0();
77938 if (!duk_unicode_is_identifier_part(x)) {
77939 break;
77940 }
77941 x = DUK__L0(); /* re-read to avoid spill / fetch */
77942 DUK__APPENDBUFFER(lex_ctx, x);
77943 DUK__ADVANCECHARS(lex_ctx, 1);
77944 }
77945 out_token->str2 = duk__internbuffer(lex_ctx, lex_ctx->slot2_idx);
77946
77947 DUK__INITBUFFER(lex_ctx); /* free some memory */
77948
77949 /* validation of the regexp is caller's responsibility */
77950
77951 advtok = DUK__ADVTOK(0, DUK_TOK_REGEXP);
77952#else /* DUK_USE_REGEXP_SUPPORT */
77953 goto fail_regexp_support;
77954#endif /* DUK_USE_REGEXP_SUPPORT */
77955 } else if (DUK__L1() == DUK_ASC_EQUALS) {
77956 /* "/=" and not in regexp mode */
77957 advtok = DUK__ADVTOK(2, DUK_TOK_DIV_EQ);
77958 } else {
77959 /* "/" and not in regexp mode */
77960 advtok = DUK__ADVTOK(1, DUK_TOK_DIV);
77961 }
77962 break;
77963 case DUK_ASC_LCURLY: /* '{' */
77964 advtok = DUK__ADVTOK(1, DUK_TOK_LCURLY);
77965 break;
77966 case DUK_ASC_RCURLY: /* '}' */
77967 advtok = DUK__ADVTOK(1, DUK_TOK_RCURLY);
77968 break;
77969 case DUK_ASC_LPAREN: /* '(' */
77970 advtok = DUK__ADVTOK(1, DUK_TOK_LPAREN);
77971 break;
77972 case DUK_ASC_RPAREN: /* ')' */
77973 advtok = DUK__ADVTOK(1, DUK_TOK_RPAREN);
77974 break;
77975 case DUK_ASC_LBRACKET: /* '[' */
77976 advtok = DUK__ADVTOK(1, DUK_TOK_LBRACKET);
77977 break;
77978 case DUK_ASC_RBRACKET: /* ']' */
77979 advtok = DUK__ADVTOK(1, DUK_TOK_RBRACKET);
77980 break;
77981 case DUK_ASC_PERIOD: /* '.' */
77982 if (DUK__ISDIGIT(DUK__L1())) {
77983 /* Period followed by a digit can only start DecimalLiteral
77984 * (handled in slow path). We could jump straight into the
77985 * DecimalLiteral handling but should avoid goto to inside
77986 * a block.
77987 */
77988 goto slow_path;
77989 }
77990 advtok = DUK__ADVTOK(1, DUK_TOK_PERIOD);
77991 break;
77992 case DUK_ASC_SEMICOLON: /* ';' */
77993 advtok = DUK__ADVTOK(1, DUK_TOK_SEMICOLON);
77994 break;
77995 case DUK_ASC_COMMA: /* ',' */
77996 advtok = DUK__ADVTOK(1, DUK_TOK_COMMA);
77997 break;
77998 case DUK_ASC_LANGLE: /* '<' */
77999 if (DUK__L1() == DUK_ASC_LANGLE && DUK__L2() == DUK_ASC_EQUALS) {
78000 advtok = DUK__ADVTOK(3, DUK_TOK_ALSHIFT_EQ);
78001 } else if (DUK__L1() == DUK_ASC_EQUALS) {
78002 advtok = DUK__ADVTOK(2, DUK_TOK_LE);
78003 } else if (DUK__L1() == DUK_ASC_LANGLE) {
78004 advtok = DUK__ADVTOK(2, DUK_TOK_ALSHIFT);
78005 } else {
78006 advtok = DUK__ADVTOK(1, DUK_TOK_LT);
78007 }
78008 break;
78009 case DUK_ASC_RANGLE: /* '>' */
78010 if (DUK__L1() == DUK_ASC_RANGLE && DUK__L2() == DUK_ASC_RANGLE && DUK__L3() == DUK_ASC_EQUALS) {
78011 advtok = DUK__ADVTOK(4, DUK_TOK_RSHIFT_EQ);
78012 } else if (DUK__L1() == DUK_ASC_RANGLE && DUK__L2() == DUK_ASC_RANGLE) {
78013 advtok = DUK__ADVTOK(3, DUK_TOK_RSHIFT);
78014 } else if (DUK__L1() == DUK_ASC_RANGLE && DUK__L2() == DUK_ASC_EQUALS) {
78015 advtok = DUK__ADVTOK(3, DUK_TOK_ARSHIFT_EQ);
78016 } else if (DUK__L1() == DUK_ASC_EQUALS) {
78017 advtok = DUK__ADVTOK(2, DUK_TOK_GE);
78018 } else if (DUK__L1() == DUK_ASC_RANGLE) {
78019 advtok = DUK__ADVTOK(2, DUK_TOK_ARSHIFT);
78020 } else {
78021 advtok = DUK__ADVTOK(1, DUK_TOK_GT);
78022 }
78023 break;
78024 case DUK_ASC_EQUALS: /* '=' */
78025 if (DUK__L1() == DUK_ASC_EQUALS && DUK__L2() == DUK_ASC_EQUALS) {
78026 advtok = DUK__ADVTOK(3, DUK_TOK_SEQ);
78027 } else if (DUK__L1() == DUK_ASC_EQUALS) {
78028 advtok = DUK__ADVTOK(2, DUK_TOK_EQ);
78029 } else {
78030 advtok = DUK__ADVTOK(1, DUK_TOK_EQUALSIGN);
78031 }
78032 break;
78033 case DUK_ASC_EXCLAMATION: /* '!' */
78034 if (DUK__L1() == DUK_ASC_EQUALS && DUK__L2() == DUK_ASC_EQUALS) {
78035 advtok = DUK__ADVTOK(3, DUK_TOK_SNEQ);
78036 } else if (DUK__L1() == DUK_ASC_EQUALS) {
78037 advtok = DUK__ADVTOK(2, DUK_TOK_NEQ);
78038 } else {
78039 advtok = DUK__ADVTOK(1, DUK_TOK_LNOT);
78040 }
78041 break;
78042 case DUK_ASC_PLUS: /* '+' */
78043 if (DUK__L1() == DUK_ASC_PLUS) {
78044 advtok = DUK__ADVTOK(2, DUK_TOK_INCREMENT);
78045 } else if (DUK__L1() == DUK_ASC_EQUALS) {
78046 advtok = DUK__ADVTOK(2, DUK_TOK_ADD_EQ);
78047 } else {
78048 advtok = DUK__ADVTOK(1, DUK_TOK_ADD);
78049 }
78050 break;
78051 case DUK_ASC_MINUS: /* '-' */
78052 if (DUK__L1() == DUK_ASC_MINUS) {
78053 advtok = DUK__ADVTOK(2, DUK_TOK_DECREMENT);
78054 } else if (DUK__L1() == DUK_ASC_EQUALS) {
78055 advtok = DUK__ADVTOK(2, DUK_TOK_SUB_EQ);
78056 } else {
78057 advtok = DUK__ADVTOK(1, DUK_TOK_SUB);
78058 }
78059 break;
78060 case DUK_ASC_STAR: /* '*' */
78061#if defined(DUK_USE_ES7_EXP_OPERATOR)
78062 if (DUK__L1() == DUK_ASC_STAR && DUK__L2() == DUK_ASC_EQUALS) {
78063 advtok = DUK__ADVTOK(3, DUK_TOK_EXP_EQ);
78064 } else if (DUK__L1() == DUK_ASC_STAR) {
78065 advtok = DUK__ADVTOK(2, DUK_TOK_EXP);
78066 } else
78067#endif
78068 if (DUK__L1() == DUK_ASC_EQUALS) {
78069 advtok = DUK__ADVTOK(2, DUK_TOK_MUL_EQ);
78070 } else {
78071 advtok = DUK__ADVTOK(1, DUK_TOK_MUL);
78072 }
78073 break;
78074 case DUK_ASC_PERCENT: /* '%' */
78075 if (DUK__L1() == DUK_ASC_EQUALS) {
78076 advtok = DUK__ADVTOK(2, DUK_TOK_MOD_EQ);
78077 } else {
78078 advtok = DUK__ADVTOK(1, DUK_TOK_MOD);
78079 }
78080 break;
78081 case DUK_ASC_AMP: /* '&' */
78082 if (DUK__L1() == DUK_ASC_AMP) {
78083 advtok = DUK__ADVTOK(2, DUK_TOK_LAND);
78084 } else if (DUK__L1() == DUK_ASC_EQUALS) {
78085 advtok = DUK__ADVTOK(2, DUK_TOK_BAND_EQ);
78086 } else {
78087 advtok = DUK__ADVTOK(1, DUK_TOK_BAND);
78088 }
78089 break;
78090 case DUK_ASC_PIPE: /* '|' */
78091 if (DUK__L1() == DUK_ASC_PIPE) {
78092 advtok = DUK__ADVTOK(2, DUK_TOK_LOR);
78093 } else if (DUK__L1() == DUK_ASC_EQUALS) {
78094 advtok = DUK__ADVTOK(2, DUK_TOK_BOR_EQ);
78095 } else {
78096 advtok = DUK__ADVTOK(1, DUK_TOK_BOR);
78097 }
78098 break;
78099 case DUK_ASC_CARET: /* '^' */
78100 if (DUK__L1() == DUK_ASC_EQUALS) {
78101 advtok = DUK__ADVTOK(2, DUK_TOK_BXOR_EQ);
78102 } else {
78103 advtok = DUK__ADVTOK(1, DUK_TOK_BXOR);
78104 }
78105 break;
78106 case DUK_ASC_TILDE: /* '~' */
78107 advtok = DUK__ADVTOK(1, DUK_TOK_BNOT);
78108 break;
78109 case DUK_ASC_QUESTION: /* '?' */
78110 advtok = DUK__ADVTOK(1, DUK_TOK_QUESTION);
78111 break;
78112 case DUK_ASC_COLON: /* ':' */
78113 advtok = DUK__ADVTOK(1, DUK_TOK_COLON);
78114 break;
78115 case DUK_ASC_DOUBLEQUOTE: /* '"' */
78116 case DUK_ASC_SINGLEQUOTE: { /* '\'' */
78117 DUK__INITBUFFER(lex_ctx);
78118 duk__lexer_parse_string_literal(lex_ctx, out_token, x /*quote*/, strict_mode);
78119 duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
78120 out_token->str1 = duk_known_hstring((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
78121
78122 DUK__INITBUFFER(lex_ctx); /* free some memory */
78123
78124 advtok = DUK__ADVTOK(0, DUK_TOK_STRING);
78125 break;
78126 }
78127 default:
78128 goto slow_path;
78129 } /* switch */
78130
78131 goto skip_slow_path;
78132
78133 slow_path:
78134 if (duk_unicode_is_line_terminator(x)) {
78135 if (x == 0x000d && DUK__L1() == 0x000a) {
78136 /*
78137 * E5 Section 7.3: CR LF is detected as a single line terminator for
78138 * line numbers. Here we also detect it as a single line terminator
78139 * token.
78140 */
78141 DUK__ADVANCECHARS(lex_ctx, 2);
78142 } else {
78143 DUK__ADVANCECHARS(lex_ctx, 1);
78144 }
78145 got_lineterm = 1;
78146 goto restart_lineupdate;
78147 } else if (duk_unicode_is_identifier_start(x) || x == DUK_ASC_BACKSLASH) {
78148 /*
78149 * Parse an identifier and then check whether it is:
78150 * - reserved word (keyword or other reserved word)
78151 * - "null" (NullLiteral)
78152 * - "true" (BooleanLiteral)
78153 * - "false" (BooleanLiteral)
78154 * - anything else => identifier
78155 *
78156 * This does not follow the E5 productions cleanly, but is
78157 * useful and compact.
78158 *
78159 * Note that identifiers may contain Unicode escapes,
78160 * see E5 Sections 6 and 7.6. They must be decoded first,
78161 * and the result checked against allowed characters.
78162 * The above if-clause accepts an identifier start and an
78163 * '\' character -- no other token can begin with a '\'.
78164 *
78165 * Note that "get" and "set" are not reserved words in E5
78166 * specification so they are recognized as plain identifiers
78167 * (the tokens DUK_TOK_GET and DUK_TOK_SET are actually not
78168 * used now). The compiler needs to work around this.
78169 *
78170 * Strictly speaking, following Ecmascript longest match
78171 * specification, an invalid escape for the first character
78172 * should cause a syntax error. However, an invalid escape
78173 * for IdentifierParts should just terminate the identifier
78174 * early (longest match), and let the next tokenization
78175 * fail. For instance Rhino croaks with 'foo\z' when
78176 * parsing the identifier. This has little practical impact.
78177 */
78178
78179 duk_small_int_t i, i_end;
78180 duk_bool_t first = 1;
78181 duk_hstring *str;
78182
78183 DUK__INITBUFFER(lex_ctx);
78184 for (;;) {
78185 /* re-lookup first char on first loop */
78186 if (DUK__L0() == DUK_ASC_BACKSLASH) {
78187 duk_codepoint_t esc_cp;
78188 if (DUK__L1() != DUK_ASC_LC_U) {
78189 goto fail_escape;
78190 }
78191 esc_cp = duk__lexer_parse_escape(lex_ctx, 1 /*allow_es6*/);
78192 DUK__APPENDBUFFER(lex_ctx, esc_cp);
78193
78194 /* IdentifierStart is stricter than IdentifierPart, so if the first
78195 * character is escaped, must have a stricter check here.
78196 */
78197 if (!(first ? duk_unicode_is_identifier_start(esc_cp) : duk_unicode_is_identifier_part(esc_cp))) {
78198 goto fail_escape;
78199 }
78200
78201 /* Track number of escapes: necessary for proper keyword
78202 * detection.
78203 */
78204 out_token->num_escapes++;
78205 } else {
78206 /* Note: first character is checked against this. But because
78207 * IdentifierPart includes all IdentifierStart characters, and
78208 * the first character (if unescaped) has already been checked
78209 * in the if condition, this is OK.
78210 */
78211 if (!duk_unicode_is_identifier_part(DUK__L0())) {
78212 break;
78213 }
78214 DUK__APPENDBUFFER(lex_ctx, DUK__L0());
78215 DUK__ADVANCECHARS(lex_ctx, 1);
78216 }
78217 first = 0;
78218 }
78219
78220 out_token->str1 = duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
78221 str = out_token->str1;
78222 out_token->t_nores = DUK_TOK_IDENTIFIER;
78223
78224 DUK__INITBUFFER(lex_ctx); /* free some memory */
78225
78226 /*
78227 * Interned identifier is compared against reserved words, which are
78228 * currently interned into the heap context. See genbuiltins.py.
78229 *
78230 * Note that an escape in the identifier disables recognition of
78231 * keywords; e.g. "\u0069f = 1;" is a valid statement (assigns to
78232 * identifier named "if"). This is not necessarily compliant,
78233 * see test-dec-escaped-char-in-keyword.js.
78234 *
78235 * Note: "get" and "set" are awkward. They are not officially
78236 * ReservedWords (and indeed e.g. "var set = 1;" is valid), and
78237 * must come out as DUK_TOK_IDENTIFIER. The compiler needs to
78238 * work around this a bit.
78239 */
78240
78241 /* XXX: optimize by adding the token numbers directly into the
78242 * always interned duk_hstring objects (there should be enough
78243 * flag bits free for that)?
78244 */
78245
78246 i_end = (strict_mode ? DUK_STRIDX_END_RESERVED : DUK_STRIDX_START_STRICT_RESERVED);
78247
78248 advtok = DUK__ADVTOK(0, DUK_TOK_IDENTIFIER);
78249 if (out_token->num_escapes == 0) {
78250 for (i = DUK_STRIDX_START_RESERVED; i < i_end; i++) {
78251 DUK_ASSERT(i >= 0 && i < DUK_HEAP_NUM_STRINGS);
78252 if (DUK_HTHREAD_GET_STRING(lex_ctx->thr, i) == str) {
78253 advtok = DUK__ADVTOK(0, DUK_STRIDX_TO_TOK(i));
78254 break;
78255 }
78256 }
78257 }
78258 } else if (DUK__ISDIGIT(x) || (x == DUK_ASC_PERIOD)) {
78259 /* Note: decimal number may start with a period, but must be followed by a digit */
78260
78261 /*
78262 * Pre-parsing for decimal, hex, octal (both legacy and ES2015),
78263 * and binary literals, followed by an actual parser step
78264 * provided by numconv.
78265 *
78266 * Note: the leading sign character ('+' or '-') is -not- part of
78267 * the production in E5 grammar, and that the a DecimalLiteral
78268 * starting with a '0' must be followed by a non-digit.
78269 *
78270 * XXX: the two step parsing process is quite awkward, it would
78271 * be more straightforward to allow numconv to parse the longest
78272 * valid prefix (it already does that, it only needs to indicate
78273 * where the input ended). However, the lexer decodes characters
78274 * using a limited lookup window, so this is not a trivial change.
78275 */
78276
78277 /* XXX: because of the final check below (that the literal is not
78278 * followed by a digit), this could maybe be simplified, if we bail
78279 * out early from a leading zero (and if there are no periods etc).
78280 * Maybe too complex.
78281 */
78282
78283 duk_double_t val;
78284 duk_bool_t legacy_oct = 0;
78285 duk_small_int_t state; /* 0=before period/exp,
78286 * 1=after period, before exp
78287 * 2=after exp, allow '+' or '-'
78288 * 3=after exp and exp sign
78289 */
78290 duk_small_uint_t s2n_flags;
78291 duk_codepoint_t y, z;
78292 duk_small_uint_t s2n_radix = 10;
78293 duk_small_uint_t pre_adv = 0;
78294
78295 DUK__INITBUFFER(lex_ctx);
78296 y = DUK__L1();
78297
78298 if (x == DUK_ASC_0) {
78299 z = DUK_LOWERCASE_CHAR_ASCII(y);
78300
78301 pre_adv = 2; /* default for 0xNNN, 0oNNN, 0bNNN. */
78302 if (z == DUK_ASC_LC_X) {
78303 s2n_radix = 16;
78304 } else if (z == DUK_ASC_LC_O) {
78305 s2n_radix = 8;
78306 } else if (z == DUK_ASC_LC_B) {
78307 s2n_radix = 2;
78308 } else {
78309 pre_adv = 0;
78310 if (DUK__ISDIGIT(y)) {
78311 if (strict_mode) {
78312 /* Reject octal like \07 but also octal-lookalike
78313 * decimal like \08 in strict mode.
78314 */
78315 goto fail_number_literal;
78316 } else {
78317 /* Legacy OctalIntegerLiteral or octal-lookalice
78318 * decimal. Deciding between the two happens below
78319 * in digit scanning.
78320 */
78321 DUK__APPENDBUFFER(lex_ctx, x);
78322 pre_adv = 1;
78323 legacy_oct = 1;
78324 s2n_radix = 8; /* tentative unless conflicting digits found */
78325 }
78326 }
78327 }
78328 }
78329
78330 DUK__ADVANCECHARS(lex_ctx, pre_adv);
78331
78332 /* XXX: we could parse integers here directly, and fall back
78333 * to numconv only when encountering a fractional expression
78334 * or when an octal literal turned out to be decimal (0778 etc).
78335 */
78336 state = 0;
78337 for (;;) {
78338 x = DUK__L0(); /* re-lookup curr char on first round */
78339 if (DUK__ISDIGIT(x)) {
78340 /* Note: intentionally allow leading zeroes here, as the
78341 * actual parser will check for them.
78342 */
78343 if (state == 0 && legacy_oct && (x == DUK_ASC_8 || x == DUK_ASC_9)) {
78344 /* Started out as an octal-lookalike
78345 * but interpreted as decimal, e.g.
78346 * '0779' -> 779. This also means
78347 * that fractions are allowed, e.g.
78348 * '0779.123' is allowed but '0777.123'
78349 * is not!
78350 */
78351 s2n_radix = 10;
78352 }
78353 if (state == 2) {
78354 state = 3;
78355 }
78356 } else if (s2n_radix == 16 && DUK__ISHEXDIGIT(x)) {
78357 /* Note: 'e' and 'E' are also accepted here. */
78358 ;
78359 } else if (x == DUK_ASC_PERIOD) {
78360 if (state >= 1 || s2n_radix != 10) {
78361 break;
78362 } else {
78363 state = 1;
78364 }
78365 } else if (x == DUK_ASC_LC_E || x == DUK_ASC_UC_E) {
78366 if (state >= 2 || s2n_radix != 10) {
78367 break;
78368 } else {
78369 state = 2;
78370 }
78371 } else if (x == DUK_ASC_MINUS || x == DUK_ASC_PLUS) {
78372 if (state != 2) {
78373 break;
78374 } else {
78375 state = 3;
78376 }
78377 } else {
78378 break;
78379 }
78380 DUK__APPENDBUFFER(lex_ctx, x);
78381 DUK__ADVANCECHARS(lex_ctx, 1);
78382 }
78383
78384 /* XXX: better coercion */
78385 (void) duk__internbuffer(lex_ctx, lex_ctx->slot1_idx);
78386
78387 if (s2n_radix != 10) {
78388 /* For bases other than 10, integer only. */
78389 s2n_flags = DUK_S2N_FLAG_ALLOW_LEADING_ZERO;
78390 } else {
78391 s2n_flags = DUK_S2N_FLAG_ALLOW_EXP |
78392 DUK_S2N_FLAG_ALLOW_FRAC |
78393 DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
78394 DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
78395 DUK_S2N_FLAG_ALLOW_LEADING_ZERO;
78396 }
78397
78398 duk_dup((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx);
78399 duk_numconv_parse((duk_context *) lex_ctx->thr, s2n_radix, s2n_flags);
78400 val = duk_to_number_m1((duk_context *) lex_ctx->thr);
78401 if (DUK_ISNAN(val)) {
78402 goto fail_number_literal;
78403 }
78404 duk_replace((duk_context *) lex_ctx->thr, lex_ctx->slot1_idx); /* could also just pop? */
78405
78406 DUK__INITBUFFER(lex_ctx); /* free some memory */
78407
78408 /* Section 7.8.3 (note): NumericLiteral must be followed by something other than
78409 * IdentifierStart or DecimalDigit.
78410 */
78411
78412 if (DUK__ISDIGIT(DUK__L0()) || duk_unicode_is_identifier_start(DUK__L0())) {
78413 goto fail_number_literal;
78414 }
78415
78416 out_token->num = val;
78417 advtok = DUK__ADVTOK(0, DUK_TOK_NUMBER);
78418 } else if (duk_unicode_is_whitespace(DUK__LOOKUP(lex_ctx, 0))) {
78419 DUK__ADVANCECHARS(lex_ctx, 1);
78420 goto restart;
78421 } else if (x < 0) {
78422 advtok = DUK__ADVTOK(0, DUK_TOK_EOF);
78423 } else {
78424 goto fail_token;
78425 }
78426 skip_slow_path:
78427
78428 /*
78429 * Shared exit path
78430 */
78431
78432 DUK__ADVANCEBYTES(lex_ctx, advtok >> 8);
78433 out_token->t = advtok & 0xff;
78434 if (out_token->t_nores < 0) {
78435 out_token->t_nores = out_token->t;
78436 }
78437 out_token->lineterm = got_lineterm;
78438
78439 /* Automatic semicolon insertion is allowed if a token is preceded
78440 * by line terminator(s), or terminates a statement list (right curly
78441 * or EOF).
78442 */
78443 if (got_lineterm || out_token->t == DUK_TOK_RCURLY || out_token->t == DUK_TOK_EOF) {
78444 out_token->allow_auto_semi = 1;
78445 } else {
78446 out_token->allow_auto_semi = 0;
78447 }
78448
78449 return;
78450
78451 fail_token_limit:
78452 DUK_ERROR_RANGE(lex_ctx->thr, DUK_STR_TOKEN_LIMIT);
78453 return;
78454
78455 fail_token:
78456 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_TOKEN);
78457 return;
78458
78459 fail_number_literal:
78460 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_NUMBER_LITERAL);
78461 return;
78462
78463 fail_escape:
78464 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_ESCAPE);
78465 return;
78466
78467 fail_unterm_regexp:
78468 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_REGEXP);
78469 return;
78470
78471 fail_unterm_comment:
78472 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_COMMENT);
78473 return;
78474
78475#if !defined(DUK_USE_REGEXP_SUPPORT)
78476 fail_regexp_support:
78477 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_REGEXP_SUPPORT_DISABLED);
78478 return;
78479#endif
78480}
78481
78482#if defined(DUK_USE_REGEXP_SUPPORT)
78483
78484/*
78485 * Parse a RegExp token. The grammar is described in E5 Section 15.10.
78486 * Terminal constructions (such as quantifiers) are parsed directly here.
78487 *
78488 * 0xffffffffU is used as a marker for "infinity" in quantifiers. Further,
78489 * DUK__MAX_RE_QUANT_DIGITS limits the maximum number of digits that
78490 * will be accepted for a quantifier.
78491 */
78492
78493DUK_INTERNAL void duk_lexer_parse_re_token(duk_lexer_ctx *lex_ctx, duk_re_token *out_token) {
78494 duk_small_int_t advtok = 0; /* init is unnecessary but suppresses "may be used uninitialized" warnings */
78495 duk_codepoint_t x, y;
78496
78497 if (++lex_ctx->token_count >= lex_ctx->token_limit) {
78498 goto fail_token_limit;
78499 }
78500
78501 DUK_MEMZERO(out_token, sizeof(*out_token));
78502
78503 x = DUK__L0();
78504 y = DUK__L1();
78505
78506 DUK_DDD(DUK_DDDPRINT("parsing regexp token, L0=%ld, L1=%ld", (long) x, (long) y));
78507
78508 switch (x) {
78509 case DUK_ASC_PIPE: {
78510 advtok = DUK__ADVTOK(1, DUK_RETOK_DISJUNCTION);
78511 break;
78512 }
78513 case DUK_ASC_CARET: {
78514 advtok = DUK__ADVTOK(1, DUK_RETOK_ASSERT_START);
78515 break;
78516 }
78517 case DUK_ASC_DOLLAR: {
78518 advtok = DUK__ADVTOK(1, DUK_RETOK_ASSERT_END);
78519 break;
78520 }
78521 case DUK_ASC_QUESTION: {
78522 out_token->qmin = 0;
78523 out_token->qmax = 1;
78524 if (y == DUK_ASC_QUESTION) {
78525 advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER);
78526 out_token->greedy = 0;
78527 } else {
78528 advtok = DUK__ADVTOK(1, DUK_RETOK_QUANTIFIER);
78529 out_token->greedy = 1;
78530 }
78531 break;
78532 }
78533 case DUK_ASC_STAR: {
78534 out_token->qmin = 0;
78535 out_token->qmax = DUK_RE_QUANTIFIER_INFINITE;
78536 if (y == DUK_ASC_QUESTION) {
78537 advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER);
78538 out_token->greedy = 0;
78539 } else {
78540 advtok = DUK__ADVTOK(1, DUK_RETOK_QUANTIFIER);
78541 out_token->greedy = 1;
78542 }
78543 break;
78544 }
78545 case DUK_ASC_PLUS: {
78546 out_token->qmin = 1;
78547 out_token->qmax = DUK_RE_QUANTIFIER_INFINITE;
78548 if (y == DUK_ASC_QUESTION) {
78549 advtok = DUK__ADVTOK(2, DUK_RETOK_QUANTIFIER);
78550 out_token->greedy = 0;
78551 } else {
78552 advtok = DUK__ADVTOK(1, DUK_RETOK_QUANTIFIER);
78553 out_token->greedy = 1;
78554 }
78555 break;
78556 }
78557 case DUK_ASC_LCURLY: {
78558 /* Production allows 'DecimalDigits', including leading zeroes */
78559 duk_uint_fast32_t val1 = 0;
78560 duk_uint_fast32_t val2 = DUK_RE_QUANTIFIER_INFINITE;
78561 duk_small_int_t digits = 0;
78562#if defined(DUK_USE_ES6_REGEXP_SYNTAX)
78563 duk_lexer_point lex_pt;
78564#endif
78565
78566#if defined(DUK_USE_ES6_REGEXP_SYNTAX)
78567 /* Store lexer position, restoring if quantifier is invalid. */
78568 DUK_LEXER_GETPOINT(lex_ctx, &lex_pt);
78569#endif
78570
78571 for (;;) {
78572 DUK__ADVANCECHARS(lex_ctx, 1); /* eat '{' on entry */
78573 x = DUK__L0();
78574 if (DUK__ISDIGIT(x)) {
78575 digits++;
78576 val1 = val1 * 10 + (duk_uint_fast32_t) duk__hexval(x);
78577 } else if (x == DUK_ASC_COMMA) {
78578 if (digits > DUK__MAX_RE_QUANT_DIGITS) {
78579 goto invalid_quantifier;
78580 }
78581 if (val2 != DUK_RE_QUANTIFIER_INFINITE) {
78582 goto invalid_quantifier;
78583 }
78584 if (DUK__L1() == DUK_ASC_RCURLY) {
78585 /* form: { DecimalDigits , }, val1 = min count */
78586 if (digits == 0) {
78587 goto invalid_quantifier;
78588 }
78589 out_token->qmin = val1;
78590 out_token->qmax = DUK_RE_QUANTIFIER_INFINITE;
78591 DUK__ADVANCECHARS(lex_ctx, 2);
78592 break;
78593 }
78594 val2 = val1;
78595 val1 = 0;
78596 digits = 0; /* not strictly necessary because of lookahead '}' above */
78597 } else if (x == DUK_ASC_RCURLY) {
78598 if (digits > DUK__MAX_RE_QUANT_DIGITS) {
78599 goto invalid_quantifier;
78600 }
78601 if (digits == 0) {
78602 goto invalid_quantifier;
78603 }
78604 if (val2 != DUK_RE_QUANTIFIER_INFINITE) {
78605 /* val2 = min count, val1 = max count */
78606 out_token->qmin = val2;
78607 out_token->qmax = val1;
78608 } else {
78609 /* val1 = count */
78610 out_token->qmin = val1;
78611 out_token->qmax = val1;
78612 }
78613 DUK__ADVANCECHARS(lex_ctx, 1);
78614 break;
78615 } else {
78616 goto invalid_quantifier;
78617 }
78618 }
78619 if (DUK__L0() == DUK_ASC_QUESTION) {
78620 out_token->greedy = 0;
78621 DUK__ADVANCECHARS(lex_ctx, 1);
78622 } else {
78623 out_token->greedy = 1;
78624 }
78625 advtok = DUK__ADVTOK(0, DUK_RETOK_QUANTIFIER);
78626 break;
78627 invalid_quantifier:
78628#if defined(DUK_USE_ES6_REGEXP_SYNTAX)
78629 /* Failed to match the quantifier, restore lexer and parse
78630 * opening brace as a literal.
78631 */
78632 DUK_LEXER_SETPOINT(lex_ctx, &lex_pt);
78633 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_CHAR);
78634 out_token->num = DUK_ASC_LCURLY;
78635#else
78636 goto fail_quantifier;
78637#endif
78638 break;
78639 }
78640 case DUK_ASC_PERIOD: {
78641 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_PERIOD);
78642 break;
78643 }
78644 case DUK_ASC_BACKSLASH: {
78645 /* The E5.1 specification does not seem to allow IdentifierPart characters
78646 * to be used as identity escapes. Unfortunately this includes '$', which
78647 * cannot be escaped as '\$'; it needs to be escaped e.g. as '\u0024'.
78648 * Many other implementations (including V8 and Rhino, for instance) do
78649 * accept '\$' as a valid identity escape, which is quite pragmatic, and
78650 * ES2015 Annex B relaxes the rules to allow these (and other) real world forms.
78651 */
78652
78653 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_CHAR); /* default: char escape (two chars) */
78654 if (y == DUK_ASC_LC_B) {
78655 advtok = DUK__ADVTOK(2, DUK_RETOK_ASSERT_WORD_BOUNDARY);
78656 } else if (y == DUK_ASC_UC_B) {
78657 advtok = DUK__ADVTOK(2, DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY);
78658 } else if (y == DUK_ASC_LC_F) {
78659 out_token->num = 0x000c;
78660 } else if (y == DUK_ASC_LC_N) {
78661 out_token->num = 0x000a;
78662 } else if (y == DUK_ASC_LC_T) {
78663 out_token->num = 0x0009;
78664 } else if (y == DUK_ASC_LC_R) {
78665 out_token->num = 0x000d;
78666 } else if (y == DUK_ASC_LC_V) {
78667 out_token->num = 0x000b;
78668 } else if (y == DUK_ASC_LC_C) {
78669 x = DUK__L2();
78670 if ((x >= DUK_ASC_LC_A && x <= DUK_ASC_LC_Z) ||
78671 (x >= DUK_ASC_UC_A && x <= DUK_ASC_UC_Z)) {
78672 out_token->num = (x % 32);
78673 advtok = DUK__ADVTOK(3, DUK_RETOK_ATOM_CHAR);
78674 } else {
78675 goto fail_escape;
78676 }
78677 } else if (y == DUK_ASC_LC_X || y == DUK_ASC_LC_U) {
78678 /* The token value is the Unicode codepoint without
78679 * it being decode into surrogate pair characters
78680 * here. The \u{H+} is only allowed in Unicode mode
78681 * which we don't support yet.
78682 */
78683 out_token->num = duk__lexer_parse_escape(lex_ctx, 0 /*allow_es6*/);
78684 advtok = DUK__ADVTOK(0, DUK_RETOK_ATOM_CHAR);
78685 } else if (y == DUK_ASC_LC_D) {
78686 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_DIGIT);
78687 } else if (y == DUK_ASC_UC_D) {
78688 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_DIGIT);
78689 } else if (y == DUK_ASC_LC_S) {
78690 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_WHITE);
78691 } else if (y == DUK_ASC_UC_S) {
78692 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_WHITE);
78693 } else if (y == DUK_ASC_LC_W) {
78694 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_WORD_CHAR);
78695 } else if (y == DUK_ASC_UC_W) {
78696 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_NOT_WORD_CHAR);
78697 } else if (DUK__ISDIGIT(y)) {
78698 /* E5 Section 15.10.2.11 */
78699 if (y == DUK_ASC_0) {
78700 if (DUK__ISDIGIT(DUK__L2())) {
78701 goto fail_escape;
78702 }
78703 out_token->num = 0x0000;
78704 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_CHAR);
78705 } else {
78706 /* XXX: shared parsing? */
78707 duk_uint_fast32_t val = 0;
78708 duk_small_int_t i;
78709 for (i = 0; ; i++) {
78710 if (i >= DUK__MAX_RE_DECESC_DIGITS) {
78711 goto fail_escape;
78712 }
78713 DUK__ADVANCECHARS(lex_ctx, 1); /* eat backslash on entry */
78714 x = DUK__L0();
78715 if (!DUK__ISDIGIT(x)) {
78716 break;
78717 }
78718 val = val * 10 + (duk_uint_fast32_t) duk__hexval(x);
78719 }
78720 /* DUK__L0() cannot be a digit, because the loop doesn't terminate if it is */
78721 advtok = DUK__ADVTOK(0, DUK_RETOK_ATOM_BACKREFERENCE);
78722 out_token->num = val;
78723 }
78724#if defined(DUK_USE_ES6_REGEXP_SYNTAX)
78725 } else if (y >= 0) {
78726 /* For ES2015 Annex B, accept any source character as identity
78727 * escape except 'c' which is used for control characters.
78728 * http://www.ecma-international.org/ecma-262/6.0/#sec-regular-expressions-patterns
78729 * Careful not to match end-of-buffer (<0) here.
78730 * This is not yet full ES2015 Annex B because cases above
78731 * (like hex escape) won't backtrack.
78732 */
78733 DUK_ASSERT(y != DUK_ASC_LC_C); /* covered above */
78734#else /* DUK_USE_ES6_REGEXP_SYNTAX */
78735 } else if ((y >= 0 && !duk_unicode_is_identifier_part(y)) ||
78736 y == DUK_UNICODE_CP_ZWNJ ||
78737 y == DUK_UNICODE_CP_ZWJ) {
78738 /* For ES5.1 identity escapes are not allowed for identifier
78739 * parts. This conflicts with a lot of real world code as this
78740 * doesn't e.g. allow escaping a dollar sign as /\$/, see
78741 * test-regexp-identity-escape-dollar.js.
78742 */
78743#endif /* DUK_USE_ES6_REGEXP_SYNTAX */
78744 out_token->num = y;
78745 } else {
78746 goto fail_escape;
78747 }
78748 break;
78749 }
78750 case DUK_ASC_LPAREN: {
78751 /* XXX: naming is inconsistent: ATOM_END_GROUP ends an ASSERT_START_LOOKAHEAD */
78752
78753 if (y == DUK_ASC_QUESTION) {
78754 if (DUK__L2() == DUK_ASC_EQUALS) {
78755 /* (?= */
78756 advtok = DUK__ADVTOK(3, DUK_RETOK_ASSERT_START_POS_LOOKAHEAD);
78757 } else if (DUK__L2() == DUK_ASC_EXCLAMATION) {
78758 /* (?! */
78759 advtok = DUK__ADVTOK(3, DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD);
78760 } else if (DUK__L2() == DUK_ASC_COLON) {
78761 /* (?: */
78762 advtok = DUK__ADVTOK(3, DUK_RETOK_ATOM_START_NONCAPTURE_GROUP);
78763 }
78764 } else {
78765 /* ( */
78766 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_START_CAPTURE_GROUP);
78767 }
78768 break;
78769 }
78770 case DUK_ASC_RPAREN: {
78771 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_END_GROUP);
78772 break;
78773 }
78774 case DUK_ASC_LBRACKET: {
78775 /*
78776 * To avoid creating a heavy intermediate value for the list of ranges,
78777 * only the start token ('[' or '[^') is parsed here. The regexp
78778 * compiler parses the ranges itself.
78779 */
78780
78781 /* XXX: with DUK_USE_ES6_REGEXP_SYNTAX we should allow left bracket
78782 * literal too, but it's not easy to parse without backtracking.
78783 */
78784
78785 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_START_CHARCLASS);
78786 if (y == DUK_ASC_CARET) {
78787 advtok = DUK__ADVTOK(2, DUK_RETOK_ATOM_START_CHARCLASS_INVERTED);
78788 }
78789 break;
78790 }
78791#if !defined(DUK_USE_ES6_REGEXP_SYNTAX)
78792 case DUK_ASC_RCURLY:
78793 case DUK_ASC_RBRACKET: {
78794 /* Although these could be parsed as PatternCharacters unambiguously (here),
78795 * E5 Section 15.10.1 grammar explicitly forbids these as PatternCharacters.
78796 */
78797 goto fail_invalid_char;
78798 break;
78799 }
78800#endif
78801 case -1: {
78802 /* EOF */
78803 advtok = DUK__ADVTOK(0, DUK_TOK_EOF);
78804 break;
78805 }
78806 default: {
78807 /* PatternCharacter, all excluded characters are matched by cases above */
78808 advtok = DUK__ADVTOK(1, DUK_RETOK_ATOM_CHAR);
78809 out_token->num = x;
78810 break;
78811 }
78812 }
78813
78814 /*
78815 * Shared exit path
78816 */
78817
78818 DUK__ADVANCEBYTES(lex_ctx, advtok >> 8);
78819 out_token->t = advtok & 0xff;
78820 return;
78821
78822 fail_token_limit:
78823 DUK_ERROR_RANGE(lex_ctx->thr, DUK_STR_TOKEN_LIMIT);
78824 return;
78825
78826 fail_escape:
78827 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_ESCAPE);
78828 return;
78829
78830#if !defined(DUK_USE_ES6_REGEXP_SYNTAX)
78831 fail_invalid_char:
78832 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_CHARACTER);
78833 return;
78834
78835 fail_quantifier:
78836 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_QUANTIFIER);
78837 return;
78838#endif
78839}
78840
78841/*
78842 * Special parser for character classes; calls callback for every
78843 * range parsed and returns the number of ranges present.
78844 */
78845
78846/* XXX: this duplicates functionality in duk_regexp.c where a similar loop is
78847 * required anyway. We could use that BUT we need to update the regexp compiler
78848 * 'nranges' too. Work this out a bit more cleanly to save space.
78849 */
78850
78851/* XXX: the handling of character range detection is a bit convoluted.
78852 * Try to simplify and make smaller.
78853 */
78854
78855/* XXX: logic for handling character ranges is now incorrect, it will accept
78856 * e.g. [\d-z] whereas it should croak from it? SMJS accepts this too, though.
78857 *
78858 * Needs a read through and a lot of additional tests.
78859 */
78860
78861DUK_LOCAL
78862void duk__emit_u16_direct_ranges(duk_lexer_ctx *lex_ctx,
78863 duk_re_range_callback gen_range,
78864 void *userdata,
78865 const duk_uint16_t *ranges,
78866 duk_small_int_t num) {
78867 const duk_uint16_t *ranges_end;
78868
78869 DUK_UNREF(lex_ctx);
78870
78871 ranges_end = ranges + num;
78872 while (ranges < ranges_end) {
78873 /* mark range 'direct', bypass canonicalization (see Wiki) */
78874 gen_range(userdata, (duk_codepoint_t) ranges[0], (duk_codepoint_t) ranges[1], 1);
78875 ranges += 2;
78876 }
78877}
78878
78879DUK_INTERNAL void duk_lexer_parse_re_ranges(duk_lexer_ctx *lex_ctx, duk_re_range_callback gen_range, void *userdata) {
78880 duk_codepoint_t start = -1;
78881 duk_codepoint_t ch;
78882 duk_codepoint_t x;
78883 duk_bool_t dash = 0;
78884 duk_small_int_t adv = 0;
78885
78886 DUK_DD(DUK_DDPRINT("parsing regexp ranges"));
78887
78888 for (;;) {
78889 DUK__ADVANCECHARS(lex_ctx, adv);
78890 adv = 1;
78891
78892 x = DUK__L0();
78893
78894 ch = -1; /* not strictly necessary, but avoids "uninitialized variable" warnings */
78895 DUK_UNREF(ch);
78896
78897 if (x < 0) {
78898 goto fail_unterm_charclass;
78899 } else if (x == DUK_ASC_RBRACKET) {
78900 if (start >= 0) {
78901 gen_range(userdata, start, start, 0);
78902 }
78903 DUK__ADVANCECHARS(lex_ctx, 1); /* eat ']' before finishing */
78904 break;
78905 } else if (x == DUK_ASC_MINUS) {
78906 if (start >= 0 && !dash && DUK__L0() != DUK_ASC_RBRACKET) {
78907 /* '-' as a range indicator */
78908 dash = 1;
78909 continue;
78910 } else {
78911 /* '-' verbatim */
78912 ch = x;
78913 }
78914 } else if (x == DUK_ASC_BACKSLASH) {
78915 /*
78916 * The escapes are same as outside a character class, except that \b has a
78917 * different meaning, and \B and backreferences are prohibited (see E5
78918 * Section 15.10.2.19). However, it's difficult to share code because we
78919 * handle e.g. "\n" very differently: here we generate a single character
78920 * range for it.
78921 */
78922
78923 /* XXX: ES2015 surrogate pair handling. */
78924
78925 x = DUK__L1();
78926
78927 adv = 2;
78928
78929 if (x == DUK_ASC_LC_B) {
78930 /* Note: '\b' in char class is different than outside (assertion),
78931 * '\B' is not allowed and is caught by the duk_unicode_is_identifier_part()
78932 * check below.
78933 */
78934 ch = 0x0008;
78935 } else if (x == DUK_ASC_LC_F) {
78936 ch = 0x000c;
78937 } else if (x == DUK_ASC_LC_N) {
78938 ch = 0x000a;
78939 } else if (x == DUK_ASC_LC_T) {
78940 ch = 0x0009;
78941 } else if (x == DUK_ASC_LC_R) {
78942 ch = 0x000d;
78943 } else if (x == DUK_ASC_LC_V) {
78944 ch = 0x000b;
78945 } else if (x == DUK_ASC_LC_C) {
78946 x = DUK__L2();
78947 adv = 3;
78948 if ((x >= DUK_ASC_LC_A && x <= DUK_ASC_LC_Z) ||
78949 (x >= DUK_ASC_UC_A && x <= DUK_ASC_UC_Z)) {
78950 ch = (x % 32);
78951 } else {
78952 goto fail_escape;
78953 }
78954 } else if (x == DUK_ASC_LC_X || x == DUK_ASC_LC_U) {
78955 /* The \u{H+} form is only allowed in Unicode mode which
78956 * we don't support yet.
78957 */
78958 ch = duk__lexer_parse_escape(lex_ctx, 0 /*allow_es6*/);
78959 adv = 0;
78960 } else if (x == DUK_ASC_LC_D) {
78961 duk__emit_u16_direct_ranges(lex_ctx,
78962 gen_range,
78963 userdata,
78964 duk_unicode_re_ranges_digit,
78965 sizeof(duk_unicode_re_ranges_digit) / sizeof(duk_uint16_t));
78966 ch = -1;
78967 } else if (x == DUK_ASC_UC_D) {
78968 duk__emit_u16_direct_ranges(lex_ctx,
78969 gen_range,
78970 userdata,
78971 duk_unicode_re_ranges_not_digit,
78972 sizeof(duk_unicode_re_ranges_not_digit) / sizeof(duk_uint16_t));
78973 ch = -1;
78974 } else if (x == DUK_ASC_LC_S) {
78975 duk__emit_u16_direct_ranges(lex_ctx,
78976 gen_range,
78977 userdata,
78978 duk_unicode_re_ranges_white,
78979 sizeof(duk_unicode_re_ranges_white) / sizeof(duk_uint16_t));
78980 ch = -1;
78981 } else if (x == DUK_ASC_UC_S) {
78982 duk__emit_u16_direct_ranges(lex_ctx,
78983 gen_range,
78984 userdata,
78985 duk_unicode_re_ranges_not_white,
78986 sizeof(duk_unicode_re_ranges_not_white) / sizeof(duk_uint16_t));
78987 ch = -1;
78988 } else if (x == DUK_ASC_LC_W) {
78989 duk__emit_u16_direct_ranges(lex_ctx,
78990 gen_range,
78991 userdata,
78992 duk_unicode_re_ranges_wordchar,
78993 sizeof(duk_unicode_re_ranges_wordchar) / sizeof(duk_uint16_t));
78994 ch = -1;
78995 } else if (x == DUK_ASC_UC_W) {
78996 duk__emit_u16_direct_ranges(lex_ctx,
78997 gen_range,
78998 userdata,
78999 duk_unicode_re_ranges_not_wordchar,
79000 sizeof(duk_unicode_re_ranges_not_wordchar) / sizeof(duk_uint16_t));
79001 ch = -1;
79002 } else if (DUK__ISDIGIT(x)) {
79003 /* DecimalEscape, only \0 is allowed, no leading zeroes are allowed */
79004 if (x == DUK_ASC_0 && !DUK__ISDIGIT(DUK__L2())) {
79005 ch = 0x0000;
79006 } else {
79007 goto fail_escape;
79008 }
79009#if defined(DUK_USE_ES6_REGEXP_SYNTAX)
79010 } else if (x >= 0) {
79011 /* IdentityEscape: ES2015 Annex B allows almost all
79012 * source characters here. Match anything except
79013 * EOF here.
79014 */
79015 ch = x;
79016#else /* DUK_USE_ES6_REGEXP_SYNTAX */
79017 } else if (!duk_unicode_is_identifier_part(x)) {
79018 /* IdentityEscape: ES5.1 doesn't allow identity escape
79019 * for identifier part characters, which conflicts with
79020 * some real world code. For example, it doesn't allow
79021 * /[\$]/ which is awkward.
79022 */
79023 ch = x;
79024#endif /* DUK_USE_ES6_REGEXP_SYNTAX */
79025 } else {
79026 goto fail_escape;
79027 }
79028 } else {
79029 /* character represents itself */
79030 ch = x;
79031 }
79032
79033 /* ch is a literal character here or -1 if parsed entity was
79034 * an escape such as "\s".
79035 */
79036
79037 if (ch < 0) {
79038 /* multi-character sets not allowed as part of ranges, see
79039 * E5 Section 15.10.2.15, abstract operation CharacterRange.
79040 */
79041 if (start >= 0) {
79042 if (dash) {
79043 goto fail_range;
79044 } else {
79045 gen_range(userdata, start, start, 0);
79046 start = -1;
79047 /* dash is already 0 */
79048 }
79049 }
79050 } else {
79051 if (start >= 0) {
79052 if (dash) {
79053 if (start > ch) {
79054 goto fail_range;
79055 }
79056 gen_range(userdata, start, ch, 0);
79057 start = -1;
79058 dash = 0;
79059 } else {
79060 gen_range(userdata, start, start, 0);
79061 start = ch;
79062 /* dash is already 0 */
79063 }
79064 } else {
79065 start = ch;
79066 }
79067 }
79068 }
79069
79070 return;
79071
79072 fail_escape:
79073 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_REGEXP_ESCAPE);
79074 return;
79075
79076 fail_range:
79077 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_INVALID_RANGE);
79078 return;
79079
79080 fail_unterm_charclass:
79081 DUK_ERROR_SYNTAX(lex_ctx->thr, DUK_STR_UNTERMINATED_CHARCLASS);
79082 return;
79083}
79084
79085#endif /* DUK_USE_REGEXP_SUPPORT */
79086
79087/* automatic undefs */
79088#undef DUK__ADVANCEBYTES
79089#undef DUK__ADVANCECHARS
79090#undef DUK__ADVTOK
79091#undef DUK__APPENDBUFFER
79092#undef DUK__APPENDBUFFER_ASCII
79093#undef DUK__INITBUFFER
79094#undef DUK__ISDIGIT
79095#undef DUK__ISDIGIT03
79096#undef DUK__ISDIGIT47
79097#undef DUK__ISHEXDIGIT
79098#undef DUK__ISOCTDIGIT
79099#undef DUK__L0
79100#undef DUK__L1
79101#undef DUK__L2
79102#undef DUK__L3
79103#undef DUK__L4
79104#undef DUK__L5
79105#undef DUK__LOOKUP
79106#undef DUK__MAX_RE_DECESC_DIGITS
79107#undef DUK__MAX_RE_QUANT_DIGITS
79108/*
79109 * Number-to-string and string-to-number conversions.
79110 *
79111 * Slow path number-to-string and string-to-number conversion is based on
79112 * a Dragon4 variant, with fast paths for small integers. Big integer
79113 * arithmetic is needed for guaranteeing that the conversion is correct
79114 * and uses a minimum number of digits. The big number arithmetic has a
79115 * fixed maximum size and does not require dynamic allocations.
79116 *
79117 * See: doc/number-conversion.rst.
79118 */
79119
79120/* #include duk_internal.h -> already included */
79121
79122#define DUK__IEEE_DOUBLE_EXP_BIAS 1023
79123#define DUK__IEEE_DOUBLE_EXP_MIN (-1022) /* biased exp == 0 -> denormal, exp -1022 */
79124
79125#define DUK__DIGITCHAR(x) duk_lc_digits[(x)]
79126
79127/*
79128 * Tables generated with util/gennumdigits.py.
79129 *
79130 * duk__str2num_digits_for_radix indicates, for each radix, how many input
79131 * digits should be considered significant for string-to-number conversion.
79132 * The input is also padded to this many digits to give the Dragon4
79133 * conversion enough (apparent) precision to work with.
79134 *
79135 * duk__str2num_exp_limits indicates, for each radix, the radix-specific
79136 * minimum/maximum exponent values (for a Dragon4 integer mantissa)
79137 * below and above which the number is guaranteed to underflow to zero
79138 * or overflow to Infinity. This allows parsing to keep bigint values
79139 * bounded.
79140 */
79141
79142DUK_LOCAL const duk_uint8_t duk__str2num_digits_for_radix[] = {
79143 69, 44, 35, 30, 27, 25, 23, 22, 20, 20, /* 2 to 11 */
79144 20, 19, 19, 18, 18, 17, 17, 17, 16, 16, /* 12 to 21 */
79145 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, /* 22 to 31 */
79146 14, 14, 14, 14, 14 /* 31 to 36 */
79147};
79148
79149typedef struct {
79150 duk_int16_t upper;
79151 duk_int16_t lower;
79153
79154DUK_LOCAL const duk__exp_limits duk__str2num_exp_limits[] = {
79155 { 957, -1147 }, { 605, -725 }, { 479, -575 }, { 414, -496 },
79156 { 372, -446 }, { 342, -411 }, { 321, -384 }, { 304, -364 },
79157 { 291, -346 }, { 279, -334 }, { 268, -323 }, { 260, -312 },
79158 { 252, -304 }, { 247, -296 }, { 240, -289 }, { 236, -283 },
79159 { 231, -278 }, { 227, -273 }, { 223, -267 }, { 220, -263 },
79160 { 216, -260 }, { 213, -256 }, { 210, -253 }, { 208, -249 },
79161 { 205, -246 }, { 203, -244 }, { 201, -241 }, { 198, -239 },
79162 { 196, -237 }, { 195, -234 }, { 193, -232 }, { 191, -230 },
79163 { 190, -228 }, { 188, -226 }, { 187, -225 },
79164};
79165
79166/*
79167 * Limited functionality bigint implementation.
79168 *
79169 * Restricted to non-negative numbers with less than 32 * DUK__BI_MAX_PARTS bits,
79170 * with the caller responsible for ensuring this is never exceeded. No memory
79171 * allocation (except stack) is needed for bigint computation. Operations
79172 * have been tailored for number conversion needs.
79173 *
79174 * Argument order is "assignment order", i.e. target first, then arguments:
79175 * x <- y * z --> duk__bi_mul(x, y, z);
79176 */
79177
79178/* This upper value has been experimentally determined; debug build will check
79179 * bigint size with assertions.
79180 */
79181#define DUK__BI_MAX_PARTS 37 /* 37x32 = 1184 bits */
79182
79183#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
79184#define DUK__BI_PRINT(name,x) duk__bi_print((name),(x))
79185#else
79186#define DUK__BI_PRINT(name,x)
79187#endif
79188
79189/* Current size is about 152 bytes. */
79190typedef struct {
79191 duk_small_int_t n;
79192 duk_uint32_t v[DUK__BI_MAX_PARTS]; /* low to high */
79193} duk__bigint;
79194
79195#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
79196DUK_LOCAL void duk__bi_print(const char *name, duk__bigint *x) {
79197 /* Overestimate required size; debug code so not critical to be tight. */
79198 char buf[DUK__BI_MAX_PARTS * 9 + 64];
79199 char *p = buf;
79200 duk_small_int_t i;
79201
79202 /* No NUL term checks in this debug code. */
79203 p += DUK_SPRINTF(p, "%p n=%ld", (void *) x, (long) x->n);
79204 if (x->n == 0) {
79205 p += DUK_SPRINTF(p, " 0");
79206 }
79207 for (i = x->n - 1; i >= 0; i--) {
79208 p += DUK_SPRINTF(p, " %08lx", (unsigned long) x->v[i]);
79209 }
79210
79211 DUK_DDD(DUK_DDDPRINT("%s: %s", (const char *) name, (const char *) buf));
79212}
79213#endif
79214
79215#if defined(DUK_USE_ASSERTIONS)
79216DUK_LOCAL duk_small_int_t duk__bi_is_valid(duk__bigint *x) {
79217 return (duk_small_int_t)
79218 ( ((x->n >= 0) && (x->n <= DUK__BI_MAX_PARTS)) /* is valid size */ &&
79219 ((x->n == 0) || (x->v[x->n - 1] != 0)) /* is normalized */ );
79220}
79221#endif
79222
79223DUK_LOCAL void duk__bi_normalize(duk__bigint *x) {
79224 duk_small_int_t i;
79225
79226 for (i = x->n - 1; i >= 0; i--) {
79227 if (x->v[i] != 0) {
79228 break;
79229 }
79230 }
79231
79232 /* Note: if 'x' is zero, x->n becomes 0 here */
79233 x->n = i + 1;
79234 DUK_ASSERT(duk__bi_is_valid(x));
79235}
79236
79237/* x <- y */
79238DUK_LOCAL void duk__bi_copy(duk__bigint *x, duk__bigint *y) {
79239 duk_small_int_t n;
79240
79241 n = y->n;
79242 x->n = n;
79243 if (n == 0) {
79244 return;
79245 }
79246 DUK_MEMCPY((void *) x->v, (const void *) y->v, (size_t) (sizeof(duk_uint32_t) * n));
79247}
79248
79249DUK_LOCAL void duk__bi_set_small(duk__bigint *x, duk_uint32_t v) {
79250 if (v == 0U) {
79251 x->n = 0;
79252 } else {
79253 x->n = 1;
79254 x->v[0] = v;
79255 }
79256 DUK_ASSERT(duk__bi_is_valid(x));
79257}
79258
79259/* Return value: <0 <=> x < y
79260 * 0 <=> x == y
79261 * >0 <=> x > y
79262 */
79263DUK_LOCAL int duk__bi_compare(duk__bigint *x, duk__bigint *y) {
79264 duk_small_int_t i, nx, ny;
79265 duk_uint32_t tx, ty;
79266
79267 DUK_ASSERT(duk__bi_is_valid(x));
79268 DUK_ASSERT(duk__bi_is_valid(y));
79269
79270 nx = x->n;
79271 ny = y->n;
79272 if (nx > ny) {
79273 goto ret_gt;
79274 }
79275 if (nx < ny) {
79276 goto ret_lt;
79277 }
79278 for (i = nx - 1; i >= 0; i--) {
79279 tx = x->v[i];
79280 ty = y->v[i];
79281
79282 if (tx > ty) {
79283 goto ret_gt;
79284 }
79285 if (tx < ty) {
79286 goto ret_lt;
79287 }
79288 }
79289
79290 return 0;
79291
79292 ret_gt:
79293 return 1;
79294
79295 ret_lt:
79296 return -1;
79297}
79298
79299/* x <- y + z */
79300#if defined(DUK_USE_64BIT_OPS)
79301DUK_LOCAL void duk__bi_add(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
79302 duk_uint64_t tmp;
79303 duk_small_int_t i, ny, nz;
79304
79305 DUK_ASSERT(duk__bi_is_valid(y));
79306 DUK_ASSERT(duk__bi_is_valid(z));
79307
79308 if (z->n > y->n) {
79309 duk__bigint *t;
79310 t = y; y = z; z = t;
79311 }
79312 DUK_ASSERT(y->n >= z->n);
79313
79314 ny = y->n; nz = z->n;
79315 tmp = 0U;
79316 for (i = 0; i < ny; i++) {
79317 DUK_ASSERT(i < DUK__BI_MAX_PARTS);
79318 tmp += y->v[i];
79319 if (i < nz) {
79320 tmp += z->v[i];
79321 }
79322 x->v[i] = (duk_uint32_t) (tmp & 0xffffffffUL);
79323 tmp = tmp >> 32;
79324 }
79325 if (tmp != 0U) {
79326 DUK_ASSERT(i < DUK__BI_MAX_PARTS);
79327 x->v[i++] = (duk_uint32_t) tmp;
79328 }
79329 x->n = i;
79330 DUK_ASSERT(x->n <= DUK__BI_MAX_PARTS);
79331
79332 /* no need to normalize */
79333 DUK_ASSERT(duk__bi_is_valid(x));
79334}
79335#else /* DUK_USE_64BIT_OPS */
79336DUK_LOCAL void duk__bi_add(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
79337 duk_uint32_t carry, tmp1, tmp2;
79338 duk_small_int_t i, ny, nz;
79339
79340 DUK_ASSERT(duk__bi_is_valid(y));
79341 DUK_ASSERT(duk__bi_is_valid(z));
79342
79343 if (z->n > y->n) {
79344 duk__bigint *t;
79345 t = y; y = z; z = t;
79346 }
79347 DUK_ASSERT(y->n >= z->n);
79348
79349 ny = y->n; nz = z->n;
79350 carry = 0U;
79351 for (i = 0; i < ny; i++) {
79352 /* Carry is detected based on wrapping which relies on exact 32-bit
79353 * types.
79354 */
79355 DUK_ASSERT(i < DUK__BI_MAX_PARTS);
79356 tmp1 = y->v[i];
79357 tmp2 = tmp1;
79358 if (i < nz) {
79359 tmp2 += z->v[i];
79360 }
79361
79362 /* Careful with carry condition:
79363 * - If carry not added: 0x12345678 + 0 + 0xffffffff = 0x12345677 (< 0x12345678)
79364 * - If carry added: 0x12345678 + 1 + 0xffffffff = 0x12345678 (== 0x12345678)
79365 */
79366 if (carry) {
79367 tmp2++;
79368 carry = (tmp2 <= tmp1 ? 1U : 0U);
79369 } else {
79370 carry = (tmp2 < tmp1 ? 1U : 0U);
79371 }
79372
79373 x->v[i] = tmp2;
79374 }
79375 if (carry) {
79376 DUK_ASSERT(i < DUK__BI_MAX_PARTS);
79377 DUK_ASSERT(carry == 1U);
79378 x->v[i++] = carry;
79379 }
79380 x->n = i;
79381 DUK_ASSERT(x->n <= DUK__BI_MAX_PARTS);
79382
79383 /* no need to normalize */
79384 DUK_ASSERT(duk__bi_is_valid(x));
79385}
79386#endif /* DUK_USE_64BIT_OPS */
79387
79388/* x <- y + z */
79389DUK_LOCAL void duk__bi_add_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z) {
79390 duk__bigint tmp;
79391
79392 DUK_ASSERT(duk__bi_is_valid(y));
79393
79394 /* XXX: this could be optimized; there is only one call site now though */
79395 duk__bi_set_small(&tmp, z);
79396 duk__bi_add(x, y, &tmp);
79397
79398 DUK_ASSERT(duk__bi_is_valid(x));
79399}
79400
79401#if 0 /* unused */
79402/* x <- x + y, use t as temp */
79403DUK_LOCAL void duk__bi_add_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t) {
79404 duk__bi_add(t, x, y);
79405 duk__bi_copy(x, t);
79406}
79407#endif
79408
79409/* x <- y - z, require x >= y => z >= 0, i.e. y >= z */
79410#if defined(DUK_USE_64BIT_OPS)
79411DUK_LOCAL void duk__bi_sub(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
79412 duk_small_int_t i, ny, nz;
79413 duk_uint32_t ty, tz;
79414 duk_int64_t tmp;
79415
79416 DUK_ASSERT(duk__bi_is_valid(y));
79417 DUK_ASSERT(duk__bi_is_valid(z));
79418 DUK_ASSERT(duk__bi_compare(y, z) >= 0);
79419 DUK_ASSERT(y->n >= z->n);
79420
79421 ny = y->n; nz = z->n;
79422 tmp = 0;
79423 for (i = 0; i < ny; i++) {
79424 ty = y->v[i];
79425 if (i < nz) {
79426 tz = z->v[i];
79427 } else {
79428 tz = 0;
79429 }
79430 tmp = (duk_int64_t) ty - (duk_int64_t) tz + tmp;
79431 x->v[i] = (duk_uint32_t) (tmp & 0xffffffffUL);
79432 tmp = tmp >> 32; /* 0 or -1 */
79433 }
79434 DUK_ASSERT(tmp == 0);
79435
79436 x->n = i;
79437 duk__bi_normalize(x); /* need to normalize, may even cancel to 0 */
79438 DUK_ASSERT(duk__bi_is_valid(x));
79439}
79440#else
79441DUK_LOCAL void duk__bi_sub(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
79442 duk_small_int_t i, ny, nz;
79443 duk_uint32_t tmp1, tmp2, borrow;
79444
79445 DUK_ASSERT(duk__bi_is_valid(y));
79446 DUK_ASSERT(duk__bi_is_valid(z));
79447 DUK_ASSERT(duk__bi_compare(y, z) >= 0);
79448 DUK_ASSERT(y->n >= z->n);
79449
79450 ny = y->n; nz = z->n;
79451 borrow = 0U;
79452 for (i = 0; i < ny; i++) {
79453 /* Borrow is detected based on wrapping which relies on exact 32-bit
79454 * types.
79455 */
79456 tmp1 = y->v[i];
79457 tmp2 = tmp1;
79458 if (i < nz) {
79459 tmp2 -= z->v[i];
79460 }
79461
79462 /* Careful with borrow condition:
79463 * - If borrow not subtracted: 0x12345678 - 0 - 0xffffffff = 0x12345679 (> 0x12345678)
79464 * - If borrow subtracted: 0x12345678 - 1 - 0xffffffff = 0x12345678 (== 0x12345678)
79465 */
79466 if (borrow) {
79467 tmp2--;
79468 borrow = (tmp2 >= tmp1 ? 1U : 0U);
79469 } else {
79470 borrow = (tmp2 > tmp1 ? 1U : 0U);
79471 }
79472
79473 x->v[i] = tmp2;
79474 }
79475 DUK_ASSERT(borrow == 0U);
79476
79477 x->n = i;
79478 duk__bi_normalize(x); /* need to normalize, may even cancel to 0 */
79479 DUK_ASSERT(duk__bi_is_valid(x));
79480}
79481#endif
79482
79483#if 0 /* unused */
79484/* x <- y - z */
79485DUK_LOCAL void duk__bi_sub_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z) {
79486 duk__bigint tmp;
79487
79488 DUK_ASSERT(duk__bi_is_valid(y));
79489
79490 /* XXX: this could be optimized */
79491 duk__bi_set_small(&tmp, z);
79492 duk__bi_sub(x, y, &tmp);
79493
79494 DUK_ASSERT(duk__bi_is_valid(x));
79495}
79496#endif
79497
79498/* x <- x - y, use t as temp */
79499DUK_LOCAL void duk__bi_sub_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t) {
79500 duk__bi_sub(t, x, y);
79501 duk__bi_copy(x, t);
79502}
79503
79504/* x <- y * z */
79505DUK_LOCAL void duk__bi_mul(duk__bigint *x, duk__bigint *y, duk__bigint *z) {
79506 duk_small_int_t i, j, nx, nz;
79507
79508 DUK_ASSERT(duk__bi_is_valid(y));
79509 DUK_ASSERT(duk__bi_is_valid(z));
79510
79511 nx = y->n + z->n; /* max possible */
79512 DUK_ASSERT(nx <= DUK__BI_MAX_PARTS);
79513
79514 if (nx == 0) {
79515 /* Both inputs are zero; cases where only one is zero can go
79516 * through main algorithm.
79517 */
79518 x->n = 0;
79519 return;
79520 }
79521
79522 DUK_MEMZERO((void *) x->v, (size_t) (sizeof(duk_uint32_t) * nx));
79523 x->n = nx;
79524
79525 nz = z->n;
79526 for (i = 0; i < y->n; i++) {
79527#if defined(DUK_USE_64BIT_OPS)
79528 duk_uint64_t tmp = 0U;
79529 for (j = 0; j < nz; j++) {
79530 tmp += (duk_uint64_t) y->v[i] * (duk_uint64_t) z->v[j] + x->v[i+j];
79531 x->v[i+j] = (duk_uint32_t) (tmp & 0xffffffffUL);
79532 tmp = tmp >> 32;
79533 }
79534 if (tmp > 0) {
79535 DUK_ASSERT(i + j < nx);
79536 DUK_ASSERT(i + j < DUK__BI_MAX_PARTS);
79537 DUK_ASSERT(x->v[i+j] == 0U);
79538 x->v[i+j] = (duk_uint32_t) tmp;
79539 }
79540#else
79541 /*
79542 * Multiply + add + carry for 32-bit components using only 16x16->32
79543 * multiplies and carry detection based on unsigned overflow.
79544 *
79545 * 1st mult, 32-bit: (A*2^16 + B)
79546 * 2nd mult, 32-bit: (C*2^16 + D)
79547 * 3rd add, 32-bit: E
79548 * 4th add, 32-bit: F
79549 *
79550 * (AC*2^16 + B) * (C*2^16 + D) + E + F
79551 * = AC*2^32 + AD*2^16 + BC*2^16 + BD + E + F
79552 * = AC*2^32 + (AD + BC)*2^16 + (BD + E + F)
79553 * = AC*2^32 + AD*2^16 + BC*2^16 + (BD + E + F)
79554 */
79555 duk_uint32_t a, b, c, d, e, f;
79556 duk_uint32_t r, s, t;
79557
79558 a = y->v[i]; b = a & 0xffffUL; a = a >> 16;
79559
79560 f = 0;
79561 for (j = 0; j < nz; j++) {
79562 c = z->v[j]; d = c & 0xffffUL; c = c >> 16;
79563 e = x->v[i+j];
79564
79565 /* build result as: (r << 32) + s: start with (BD + E + F) */
79566 r = 0;
79567 s = b * d;
79568
79569 /* add E */
79570 t = s + e;
79571 if (t < s) { r++; } /* carry */
79572 s = t;
79573
79574 /* add F */
79575 t = s + f;
79576 if (t < s) { r++; } /* carry */
79577 s = t;
79578
79579 /* add BC*2^16 */
79580 t = b * c;
79581 r += (t >> 16);
79582 t = s + ((t & 0xffffUL) << 16);
79583 if (t < s) { r++; } /* carry */
79584 s = t;
79585
79586 /* add AD*2^16 */
79587 t = a * d;
79588 r += (t >> 16);
79589 t = s + ((t & 0xffffUL) << 16);
79590 if (t < s) { r++; } /* carry */
79591 s = t;
79592
79593 /* add AC*2^32 */
79594 t = a * c;
79595 r += t;
79596
79597 DUK_DDD(DUK_DDDPRINT("ab=%08lx cd=%08lx ef=%08lx -> rs=%08lx %08lx",
79598 (unsigned long) y->v[i], (unsigned long) z->v[j],
79599 (unsigned long) x->v[i+j], (unsigned long) r,
79600 (unsigned long) s));
79601
79602 x->v[i+j] = s;
79603 f = r;
79604 }
79605 if (f > 0U) {
79606 DUK_ASSERT(i + j < nx);
79607 DUK_ASSERT(i + j < DUK__BI_MAX_PARTS);
79608 DUK_ASSERT(x->v[i+j] == 0U);
79609 x->v[i+j] = (duk_uint32_t) f;
79610 }
79611#endif /* DUK_USE_64BIT_OPS */
79612 }
79613
79614 duk__bi_normalize(x);
79615 DUK_ASSERT(duk__bi_is_valid(x));
79616}
79617
79618/* x <- y * z */
79619DUK_LOCAL void duk__bi_mul_small(duk__bigint *x, duk__bigint *y, duk_uint32_t z) {
79620 duk__bigint tmp;
79621
79622 DUK_ASSERT(duk__bi_is_valid(y));
79623
79624 /* XXX: this could be optimized */
79625 duk__bi_set_small(&tmp, z);
79626 duk__bi_mul(x, y, &tmp);
79627
79628 DUK_ASSERT(duk__bi_is_valid(x));
79629}
79630
79631/* x <- x * y, use t as temp */
79632DUK_LOCAL void duk__bi_mul_copy(duk__bigint *x, duk__bigint *y, duk__bigint *t) {
79633 duk__bi_mul(t, x, y);
79634 duk__bi_copy(x, t);
79635}
79636
79637/* x <- x * y, use t as temp */
79638DUK_LOCAL void duk__bi_mul_small_copy(duk__bigint *x, duk_uint32_t y, duk__bigint *t) {
79639 duk__bi_mul_small(t, x, y);
79640 duk__bi_copy(x, t);
79641}
79642
79643DUK_LOCAL int duk__bi_is_even(duk__bigint *x) {
79644 DUK_ASSERT(duk__bi_is_valid(x));
79645 return (x->n == 0) || ((x->v[0] & 0x01) == 0);
79646}
79647
79648DUK_LOCAL int duk__bi_is_zero(duk__bigint *x) {
79649 DUK_ASSERT(duk__bi_is_valid(x));
79650 return (x->n == 0); /* this is the case for normalized numbers */
79651}
79652
79653/* Bigint is 2^52. Used to detect normalized IEEE double mantissa values
79654 * which are at the lowest edge (next floating point value downwards has
79655 * a different exponent). The lowest mantissa has the form:
79656 *
79657 * 1000........000 (52 zeroes; only "hidden bit" is set)
79658 */
79659DUK_LOCAL duk_small_int_t duk__bi_is_2to52(duk__bigint *x) {
79660 DUK_ASSERT(duk__bi_is_valid(x));
79661 return (duk_small_int_t)
79662 (x->n == 2) && (x->v[0] == 0U) && (x->v[1] == (1U << (52-32)));
79663}
79664
79665/* x <- (1<<y) */
79666DUK_LOCAL void duk__bi_twoexp(duk__bigint *x, duk_small_int_t y) {
79667 duk_small_int_t n, r;
79668
79669 n = (y / 32) + 1;
79670 DUK_ASSERT(n > 0);
79671 r = y % 32;
79672 DUK_MEMZERO((void *) x->v, sizeof(duk_uint32_t) * n);
79673 x->n = n;
79674 x->v[n - 1] = (((duk_uint32_t) 1) << r);
79675}
79676
79677/* x <- b^y; use t1 and t2 as temps */
79678DUK_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) {
79679 /* Fast path the binary case */
79680
79681 DUK_ASSERT(x != t1 && x != t2 && t1 != t2); /* distinct bignums, easy mistake to make */
79682 DUK_ASSERT(b >= 0);
79683 DUK_ASSERT(y >= 0);
79684
79685 if (b == 2) {
79686 duk__bi_twoexp(x, y);
79687 return;
79688 }
79689
79690 /* http://en.wikipedia.org/wiki/Exponentiation_by_squaring */
79691
79692 DUK_DDD(DUK_DDDPRINT("exp_small: b=%ld, y=%ld", (long) b, (long) y));
79693
79694 duk__bi_set_small(x, 1);
79695 duk__bi_set_small(t1, b);
79696 for (;;) {
79697 /* Loop structure ensures that we don't compute t1^2 unnecessarily
79698 * on the final round, as that might create a bignum exceeding the
79699 * current DUK__BI_MAX_PARTS limit.
79700 */
79701 if (y & 0x01) {
79702 duk__bi_mul_copy(x, t1, t2);
79703 }
79704 y = y >> 1;
79705 if (y == 0) {
79706 break;
79707 }
79708 duk__bi_mul_copy(t1, t1, t2);
79709 }
79710
79711 DUK__BI_PRINT("exp_small result", x);
79712}
79714/*
79715 * A Dragon4 number-to-string variant, based on:
79716 *
79717 * Guy L. Steele Jr., Jon L. White: "How to Print Floating-Point Numbers
79718 * Accurately"
79719 *
79720 * Robert G. Burger, R. Kent Dybvig: "Printing Floating-Point Numbers
79721 * Quickly and Accurately"
79722 *
79723 * The current algorithm is based on Figure 1 of the Burger-Dybvig paper,
79724 * i.e. the base implementation without logarithm estimation speedups
79725 * (these would increase code footprint considerably). Fixed-format output
79726 * does not follow the suggestions in the paper; instead, we generate an
79727 * extra digit and round-with-carry.
79728 *
79729 * The same algorithm is used for number parsing (with b=10 and B=2)
79730 * by generating one extra digit and doing rounding manually.
79731 *
79732 * See doc/number-conversion.rst for limitations.
79733 */
79734
79735/* Maximum number of digits generated. */
79736#define DUK__MAX_OUTPUT_DIGITS 1040 /* (Number.MAX_VALUE).toString(2).length == 1024, + spare */
79737
79738/* Maximum number of characters in formatted value. */
79739#define DUK__MAX_FORMATTED_LENGTH 1040 /* (-Number.MAX_VALUE).toString(2).length == 1025, + spare */
79740
79741/* Number and (minimum) size of bigints in the nc_ctx structure. */
79742#define DUK__NUMCONV_CTX_NUM_BIGINTS 7
79743#define DUK__NUMCONV_CTX_BIGINTS_SIZE (sizeof(duk__bigint) * DUK__NUMCONV_CTX_NUM_BIGINTS)
79744
79745typedef struct {
79746 /* Currently about 7*152 = 1064 bytes. The space for these
79747 * duk__bigints is used also as a temporary buffer for generating
79748 * the final string. This is a bit awkard; a union would be
79749 * more correct.
79750 */
79751 duk__bigint f, r, s, mp, mm, t1, t2;
79752
79753 duk_small_int_t is_s2n; /* if 1, doing a string-to-number; else doing a number-to-string */
79754 duk_small_int_t is_fixed; /* if 1, doing a fixed format output (not free format) */
79755 duk_small_int_t req_digits; /* requested number of output digits; 0 = free-format */
79756 duk_small_int_t abs_pos; /* digit position is absolute, not relative */
79757 duk_small_int_t e; /* exponent for 'f' */
79758 duk_small_int_t b; /* input radix */
79759 duk_small_int_t B; /* output radix */
79760 duk_small_int_t k; /* see algorithm */
79761 duk_small_int_t low_ok; /* see algorithm */
79762 duk_small_int_t high_ok; /* see algorithm */
79763 duk_small_int_t unequal_gaps; /* m+ != m- (very rarely) */
79764
79765 /* Buffer used for generated digits, values are in the range [0,B-1]. */
79766 duk_uint8_t digits[DUK__MAX_OUTPUT_DIGITS];
79767 duk_small_int_t count; /* digit count */
79769
79770/* Note: computes with 'idx' in assertions, so caller beware.
79771 * 'idx' is preincremented, i.e. '1' on first call, because it
79772 * is more convenient for the caller.
79773 */
79774#define DUK__DRAGON4_OUTPUT_PREINC(nc_ctx,preinc_idx,x) do { \
79775 DUK_ASSERT((preinc_idx) - 1 >= 0); \
79776 DUK_ASSERT((preinc_idx) - 1 < DUK__MAX_OUTPUT_DIGITS); \
79777 ((nc_ctx)->digits[(preinc_idx) - 1]) = (duk_uint8_t) (x); \
79778 } while (0)
79779
79780DUK_LOCAL duk_size_t duk__dragon4_format_uint32(duk_uint8_t *buf, duk_uint32_t x, duk_small_int_t radix) {
79781 duk_uint8_t *p;
79782 duk_size_t len;
79783 duk_small_int_t dig;
79784 duk_small_int_t t;
79785
79786 DUK_ASSERT(radix >= 2 && radix <= 36);
79787
79788 /* A 32-bit unsigned integer formats to at most 32 digits (the
79789 * worst case happens with radix == 2). Output the digits backwards,
79790 * and use a memmove() to get them in the right place.
79791 */
79792
79793 p = buf + 32;
79794 for (;;) {
79795 t = x / radix;
79796 dig = x - t * radix;
79797 x = t;
79798
79799 DUK_ASSERT(dig >= 0 && dig < 36);
79800 *(--p) = DUK__DIGITCHAR(dig);
79801
79802 if (x == 0) {
79803 break;
79804 }
79805 }
79806 len = (duk_size_t) ((buf + 32) - p);
79807
79808 DUK_MEMMOVE((void *) buf, (const void *) p, (size_t) len);
79809
79810 return len;
79811}
79812
79813DUK_LOCAL void duk__dragon4_prepare(duk__numconv_stringify_ctx *nc_ctx) {
79814 duk_small_int_t lowest_mantissa;
79815
79816#if 1
79817 /* Assume IEEE round-to-even, so that shorter encoding can be used
79818 * when round-to-even would produce correct result. By removing
79819 * this check (and having low_ok == high_ok == 0) the results would
79820 * still be accurate but in some cases longer than necessary.
79821 */
79822 if (duk__bi_is_even(&nc_ctx->f)) {
79823 DUK_DDD(DUK_DDDPRINT("f is even"));
79824 nc_ctx->low_ok = 1;
79825 nc_ctx->high_ok = 1;
79826 } else {
79827 DUK_DDD(DUK_DDDPRINT("f is odd"));
79828 nc_ctx->low_ok = 0;
79829 nc_ctx->high_ok = 0;
79830 }
79831#else
79832 /* Note: not honoring round-to-even should work but now generates incorrect
79833 * results. For instance, 1e23 serializes to "a000...", i.e. the first digit
79834 * equals the radix (10). Scaling stops one step too early in this case.
79835 * Don't know why this is the case, but since this code path is unused, it
79836 * doesn't matter.
79837 */
79838 nc_ctx->low_ok = 0;
79839 nc_ctx->high_ok = 0;
79840#endif
79841
79842 /* For string-to-number, pretend we never have the lowest mantissa as there
79843 * is no natural "precision" for inputs. Having lowest_mantissa == 0, we'll
79844 * fall into the base cases for both e >= 0 and e < 0.
79845 */
79846 if (nc_ctx->is_s2n) {
79847 lowest_mantissa = 0;
79848 } else {
79849 lowest_mantissa = duk__bi_is_2to52(&nc_ctx->f);
79850 }
79851
79852 nc_ctx->unequal_gaps = 0;
79853 if (nc_ctx->e >= 0) {
79854 /* exponent non-negative (and thus not minimum exponent) */
79855
79856 if (lowest_mantissa) {
79857 /* (>= e 0) AND (= f (expt b (- p 1)))
79858 *
79859 * be <- (expt b e) == b^e
79860 * be1 <- (* be b) == (expt b (+ e 1)) == b^(e+1)
79861 * r <- (* f be1 2) == 2 * f * b^(e+1) [if b==2 -> f * b^(e+2)]
79862 * s <- (* b 2) [if b==2 -> 4]
79863 * m+ <- be1 == b^(e+1)
79864 * m- <- be == b^e
79865 * k <- 0
79866 * B <- B
79867 * low_ok <- round
79868 * high_ok <- round
79869 */
79870
79871 DUK_DDD(DUK_DDDPRINT("non-negative exponent (not smallest exponent); "
79872 "lowest mantissa value for this exponent -> "
79873 "unequal gaps"));
79874
79875 duk__bi_exp_small(&nc_ctx->mm, nc_ctx->b, nc_ctx->e, &nc_ctx->t1, &nc_ctx->t2); /* mm <- b^e */
79876 duk__bi_mul_small(&nc_ctx->mp, &nc_ctx->mm, nc_ctx->b); /* mp <- b^(e+1) */
79877 duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, 2);
79878 duk__bi_mul(&nc_ctx->r, &nc_ctx->t1, &nc_ctx->mp); /* r <- (2 * f) * b^(e+1) */
79879 duk__bi_set_small(&nc_ctx->s, nc_ctx->b * 2); /* s <- 2 * b */
79880 nc_ctx->unequal_gaps = 1;
79881 } else {
79882 /* (>= e 0) AND (not (= f (expt b (- p 1))))
79883 *
79884 * be <- (expt b e) == b^e
79885 * r <- (* f be 2) == 2 * f * b^e [if b==2 -> f * b^(e+1)]
79886 * s <- 2
79887 * m+ <- be == b^e
79888 * m- <- be == b^e
79889 * k <- 0
79890 * B <- B
79891 * low_ok <- round
79892 * high_ok <- round
79893 */
79894
79895 DUK_DDD(DUK_DDDPRINT("non-negative exponent (not smallest exponent); "
79896 "not lowest mantissa for this exponent -> "
79897 "equal gaps"));
79898
79899 duk__bi_exp_small(&nc_ctx->mm, nc_ctx->b, nc_ctx->e, &nc_ctx->t1, &nc_ctx->t2); /* mm <- b^e */
79900 duk__bi_copy(&nc_ctx->mp, &nc_ctx->mm); /* mp <- b^e */
79901 duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, 2);
79902 duk__bi_mul(&nc_ctx->r, &nc_ctx->t1, &nc_ctx->mp); /* r <- (2 * f) * b^e */
79903 duk__bi_set_small(&nc_ctx->s, 2); /* s <- 2 */
79904 }
79905 } else {
79906 /* When doing string-to-number, lowest_mantissa is always 0 so
79907 * the exponent check, while incorrect, won't matter.
79908 */
79909 if (nc_ctx->e > DUK__IEEE_DOUBLE_EXP_MIN /*not minimum exponent*/ &&
79910 lowest_mantissa /* lowest mantissa for this exponent*/) {
79911 /* r <- (* f b 2) [if b==2 -> (* f 4)]
79912 * s <- (* (expt b (- 1 e)) 2) == b^(1-e) * 2 [if b==2 -> b^(2-e)]
79913 * m+ <- b == 2
79914 * m- <- 1
79915 * k <- 0
79916 * B <- B
79917 * low_ok <- round
79918 * high_ok <- round
79919 */
79920
79921 DUK_DDD(DUK_DDDPRINT("negative exponent; not minimum exponent and "
79922 "lowest mantissa for this exponent -> "
79923 "unequal gaps"));
79924
79925 duk__bi_mul_small(&nc_ctx->r, &nc_ctx->f, nc_ctx->b * 2); /* r <- (2 * b) * f */
79926 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 */
79927 duk__bi_mul_small(&nc_ctx->s, &nc_ctx->t1, 2); /* s <- b^(1-e) * 2 */
79928 duk__bi_set_small(&nc_ctx->mp, 2);
79929 duk__bi_set_small(&nc_ctx->mm, 1);
79930 nc_ctx->unequal_gaps = 1;
79931 } else {
79932 /* r <- (* f 2)
79933 * s <- (* (expt b (- e)) 2) == b^(-e) * 2 [if b==2 -> b^(1-e)]
79934 * m+ <- 1
79935 * m- <- 1
79936 * k <- 0
79937 * B <- B
79938 * low_ok <- round
79939 * high_ok <- round
79940 */
79941
79942 DUK_DDD(DUK_DDDPRINT("negative exponent; minimum exponent or not "
79943 "lowest mantissa for this exponent -> "
79944 "equal gaps"));
79945
79946 duk__bi_mul_small(&nc_ctx->r, &nc_ctx->f, 2); /* r <- 2 * f */
79947 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 */
79948 duk__bi_mul_small(&nc_ctx->s, &nc_ctx->t1, 2); /* s <- b^(-e) * 2 */
79949 duk__bi_set_small(&nc_ctx->mp, 1);
79950 duk__bi_set_small(&nc_ctx->mm, 1);
79951 }
79952 }
79953}
79954
79955DUK_LOCAL void duk__dragon4_scale(duk__numconv_stringify_ctx *nc_ctx) {
79956 duk_small_int_t k = 0;
79957
79958 /* This is essentially the 'scale' algorithm, with recursion removed.
79959 * Note that 'k' is either correct immediately, or will move in one
79960 * direction in the loop. There's no need to do the low/high checks
79961 * on every round (like the Scheme algorithm does).
79962 *
79963 * The scheme algorithm finds 'k' and updates 's' simultaneously,
79964 * while the logical algorithm finds 'k' with 's' having its initial
79965 * value, after which 's' is updated separately (see the Burger-Dybvig
79966 * paper, Section 3.1, steps 2 and 3).
79967 *
79968 * The case where m+ == m- (almost always) is optimized for, because
79969 * it reduces the bigint operations considerably and almost always
79970 * applies. The scale loop only needs to work with m+, so this works.
79971 */
79972
79973 /* XXX: this algorithm could be optimized quite a lot by using e.g.
79974 * a logarithm based estimator for 'k' and performing B^n multiplication
79975 * using a lookup table or using some bit-representation based exp
79976 * algorithm. Currently we just loop, with significant performance
79977 * impact for very large and very small numbers.
79978 */
79979
79980 DUK_DDD(DUK_DDDPRINT("scale: B=%ld, low_ok=%ld, high_ok=%ld",
79981 (long) nc_ctx->B, (long) nc_ctx->low_ok, (long) nc_ctx->high_ok));
79982 DUK__BI_PRINT("r(init)", &nc_ctx->r);
79983 DUK__BI_PRINT("s(init)", &nc_ctx->s);
79984 DUK__BI_PRINT("mp(init)", &nc_ctx->mp);
79985 DUK__BI_PRINT("mm(init)", &nc_ctx->mm);
79986
79987 for (;;) {
79988 DUK_DDD(DUK_DDDPRINT("scale loop (inc k), k=%ld", (long) k));
79989 DUK__BI_PRINT("r", &nc_ctx->r);
79990 DUK__BI_PRINT("s", &nc_ctx->s);
79991 DUK__BI_PRINT("m+", &nc_ctx->mp);
79992 DUK__BI_PRINT("m-", &nc_ctx->mm);
79993
79994 duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp); /* t1 = (+ r m+) */
79995 if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) >= (nc_ctx->high_ok ? 0 : 1)) {
79996 DUK_DDD(DUK_DDDPRINT("k is too low"));
79997 /* r <- r
79998 * s <- (* s B)
79999 * m+ <- m+
80000 * m- <- m-
80001 * k <- (+ k 1)
80002 */
80003
80004 duk__bi_mul_small_copy(&nc_ctx->s, nc_ctx->B, &nc_ctx->t1);
80005 k++;
80006 } else {
80007 break;
80008 }
80009 }
80010
80011 /* k > 0 -> k was too low, and cannot be too high */
80012 if (k > 0) {
80013 goto skip_dec_k;
80014 }
80015
80016 for (;;) {
80017 DUK_DDD(DUK_DDDPRINT("scale loop (dec k), k=%ld", (long) k));
80018 DUK__BI_PRINT("r", &nc_ctx->r);
80019 DUK__BI_PRINT("s", &nc_ctx->s);
80020 DUK__BI_PRINT("m+", &nc_ctx->mp);
80021 DUK__BI_PRINT("m-", &nc_ctx->mm);
80022
80023 duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp); /* t1 = (+ r m+) */
80024 duk__bi_mul_small(&nc_ctx->t2, &nc_ctx->t1, nc_ctx->B); /* t2 = (* (+ r m+) B) */
80025 if (duk__bi_compare(&nc_ctx->t2, &nc_ctx->s) <= (nc_ctx->high_ok ? -1 : 0)) {
80026 DUK_DDD(DUK_DDDPRINT("k is too high"));
80027 /* r <- (* r B)
80028 * s <- s
80029 * m+ <- (* m+ B)
80030 * m- <- (* m- B)
80031 * k <- (- k 1)
80032 */
80033 duk__bi_mul_small_copy(&nc_ctx->r, nc_ctx->B, &nc_ctx->t1);
80034 duk__bi_mul_small_copy(&nc_ctx->mp, nc_ctx->B, &nc_ctx->t1);
80035 if (nc_ctx->unequal_gaps) {
80036 DUK_DDD(DUK_DDDPRINT("m+ != m- -> need to update m- too"));
80037 duk__bi_mul_small_copy(&nc_ctx->mm, nc_ctx->B, &nc_ctx->t1);
80038 }
80039 k--;
80040 } else {
80041 break;
80042 }
80043 }
80044
80045 skip_dec_k:
80046
80047 if (!nc_ctx->unequal_gaps) {
80048 DUK_DDD(DUK_DDDPRINT("equal gaps, copy m- from m+"));
80049 duk__bi_copy(&nc_ctx->mm, &nc_ctx->mp); /* mm <- mp */
80050 }
80051 nc_ctx->k = k;
80052
80053 DUK_DDD(DUK_DDDPRINT("final k: %ld", (long) k));
80054 DUK__BI_PRINT("r(final)", &nc_ctx->r);
80055 DUK__BI_PRINT("s(final)", &nc_ctx->s);
80056 DUK__BI_PRINT("mp(final)", &nc_ctx->mp);
80057 DUK__BI_PRINT("mm(final)", &nc_ctx->mm);
80058}
80059
80060DUK_LOCAL void duk__dragon4_generate(duk__numconv_stringify_ctx *nc_ctx) {
80061 duk_small_int_t tc1, tc2; /* terminating conditions */
80062 duk_small_int_t d; /* current digit */
80063 duk_small_int_t count = 0; /* digit count */
80064
80065 /*
80066 * Digit generation loop.
80067 *
80068 * Different termination conditions:
80069 *
80070 * 1. Free format output. Terminate when shortest accurate
80071 * representation found.
80072 *
80073 * 2. Fixed format output, with specific number of digits.
80074 * Ignore termination conditions, terminate when digits
80075 * generated. Caller requests an extra digit and rounds.
80076 *
80077 * 3. Fixed format output, with a specific absolute cut-off
80078 * position (e.g. 10 digits after decimal point). Note
80079 * that we always generate at least one digit, even if
80080 * the digit is below the cut-off point already.
80081 */
80082
80083 for (;;) {
80084 DUK_DDD(DUK_DDDPRINT("generate loop, count=%ld, k=%ld, B=%ld, low_ok=%ld, high_ok=%ld",
80085 (long) count, (long) nc_ctx->k, (long) nc_ctx->B,
80086 (long) nc_ctx->low_ok, (long) nc_ctx->high_ok));
80087 DUK__BI_PRINT("r", &nc_ctx->r);
80088 DUK__BI_PRINT("s", &nc_ctx->s);
80089 DUK__BI_PRINT("m+", &nc_ctx->mp);
80090 DUK__BI_PRINT("m-", &nc_ctx->mm);
80091
80092 /* (quotient-remainder (* r B) s) using a dummy subtraction loop */
80093 duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->r, nc_ctx->B); /* t1 <- (* r B) */
80094 d = 0;
80095 for (;;) {
80096 if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) < 0) {
80097 break;
80098 }
80099 duk__bi_sub_copy(&nc_ctx->t1, &nc_ctx->s, &nc_ctx->t2); /* t1 <- t1 - s */
80100 d++;
80101 }
80102 duk__bi_copy(&nc_ctx->r, &nc_ctx->t1); /* r <- (remainder (* r B) s) */
80103 /* d <- (quotient (* r B) s) (in range 0...B-1) */
80104 DUK_DDD(DUK_DDDPRINT("-> d(quot)=%ld", (long) d));
80105 DUK__BI_PRINT("r(rem)", &nc_ctx->r);
80106
80107 duk__bi_mul_small_copy(&nc_ctx->mp, nc_ctx->B, &nc_ctx->t2); /* m+ <- (* m+ B) */
80108 duk__bi_mul_small_copy(&nc_ctx->mm, nc_ctx->B, &nc_ctx->t2); /* m- <- (* m- B) */
80109 DUK__BI_PRINT("mp(upd)", &nc_ctx->mp);
80110 DUK__BI_PRINT("mm(upd)", &nc_ctx->mm);
80111
80112 /* Terminating conditions. For fixed width output, we just ignore the
80113 * terminating conditions (and pretend that tc1 == tc2 == false). The
80114 * the current shortcut for fixed-format output is to generate a few
80115 * extra digits and use rounding (with carry) to finish the output.
80116 */
80117
80118 if (nc_ctx->is_fixed == 0) {
80119 /* free-form */
80120 tc1 = (duk__bi_compare(&nc_ctx->r, &nc_ctx->mm) <= (nc_ctx->low_ok ? 0 : -1));
80121
80122 duk__bi_add(&nc_ctx->t1, &nc_ctx->r, &nc_ctx->mp); /* t1 <- (+ r m+) */
80123 tc2 = (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) >= (nc_ctx->high_ok ? 0 : 1));
80124
80125 DUK_DDD(DUK_DDDPRINT("tc1=%ld, tc2=%ld", (long) tc1, (long) tc2));
80126 } else {
80127 /* fixed-format */
80128 tc1 = 0;
80129 tc2 = 0;
80130 }
80131
80132 /* Count is incremented before DUK__DRAGON4_OUTPUT_PREINC() call
80133 * on purpose, which is taken into account by the macro.
80134 */
80135 count++;
80136
80137 if (tc1) {
80138 if (tc2) {
80139 /* tc1 = true, tc2 = true */
80140 duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->r, 2);
80141 if (duk__bi_compare(&nc_ctx->t1, &nc_ctx->s) < 0) { /* (< (* r 2) s) */
80142 DUK_DDD(DUK_DDDPRINT("tc1=true, tc2=true, 2r > s: output d --> %ld (k=%ld)",
80143 (long) d, (long) nc_ctx->k));
80144 DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d);
80145 } else {
80146 DUK_DDD(DUK_DDDPRINT("tc1=true, tc2=true, 2r <= s: output d+1 --> %ld (k=%ld)",
80147 (long) (d + 1), (long) nc_ctx->k));
80148 DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d + 1);
80149 }
80150 break;
80151 } else {
80152 /* tc1 = true, tc2 = false */
80153 DUK_DDD(DUK_DDDPRINT("tc1=true, tc2=false: output d --> %ld (k=%ld)",
80154 (long) d, (long) nc_ctx->k));
80155 DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d);
80156 break;
80157 }
80158 } else {
80159 if (tc2) {
80160 /* tc1 = false, tc2 = true */
80161 DUK_DDD(DUK_DDDPRINT("tc1=false, tc2=true: output d+1 --> %ld (k=%ld)",
80162 (long) (d + 1), (long) nc_ctx->k));
80163 DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d + 1);
80164 break;
80165 } else {
80166 /* tc1 = false, tc2 = false */
80167 DUK_DDD(DUK_DDDPRINT("tc1=false, tc2=false: output d --> %ld (k=%ld)",
80168 (long) d, (long) nc_ctx->k));
80169 DUK__DRAGON4_OUTPUT_PREINC(nc_ctx, count, d);
80170
80171 /* r <- r (updated above: r <- (remainder (* r B) s)
80172 * s <- s
80173 * m+ <- m+ (updated above: m+ <- (* m+ B)
80174 * m- <- m- (updated above: m- <- (* m- B)
80175 * B, low_ok, high_ok are fixed
80176 */
80177
80178 /* fall through and continue for-loop */
80179 }
80180 }
80181
80182 /* fixed-format termination conditions */
80183 if (nc_ctx->is_fixed) {
80184 if (nc_ctx->abs_pos) {
80185 int pos = nc_ctx->k - count + 1; /* count is already incremented, take into account */
80186 DUK_DDD(DUK_DDDPRINT("fixed format, absolute: abs pos=%ld, k=%ld, count=%ld, req=%ld",
80187 (long) pos, (long) nc_ctx->k, (long) count, (long) nc_ctx->req_digits));
80188 if (pos <= nc_ctx->req_digits) {
80189 DUK_DDD(DUK_DDDPRINT("digit position reached req_digits, end generate loop"));
80190 break;
80191 }
80192 } else {
80193 DUK_DDD(DUK_DDDPRINT("fixed format, relative: k=%ld, count=%ld, req=%ld",
80194 (long) nc_ctx->k, (long) count, (long) nc_ctx->req_digits));
80195 if (count >= nc_ctx->req_digits) {
80196 DUK_DDD(DUK_DDDPRINT("digit count reached req_digits, end generate loop"));
80197 break;
80198 }
80199 }
80200 }
80201 } /* for */
80202
80203 nc_ctx->count = count;
80204
80205 DUK_DDD(DUK_DDDPRINT("generate finished"));
80206
80207#if defined(DUK_USE_DEBUG_LEVEL) && (DUK_USE_DEBUG_LEVEL >= 2)
80208 {
80209 duk_uint8_t buf[2048];
80210 duk_small_int_t i, t;
80211 DUK_MEMZERO(buf, sizeof(buf));
80212 for (i = 0; i < nc_ctx->count; i++) {
80213 t = nc_ctx->digits[i];
80214 if (t < 0 || t > 36) {
80215 buf[i] = (duk_uint8_t) '?';
80216 } else {
80217 buf[i] = (duk_uint8_t) DUK__DIGITCHAR(t);
80218 }
80219 }
80220 DUK_DDD(DUK_DDDPRINT("-> generated digits; k=%ld, digits='%s'",
80221 (long) nc_ctx->k, (const char *) buf));
80222 }
80223#endif
80224}
80225
80226/* Round up digits to a given position. If position is out-of-bounds,
80227 * does nothing. If carry propagates over the first digit, a '1' is
80228 * prepended to digits and 'k' will be updated. Return value indicates
80229 * whether carry propagated over the first digit.
80230 *
80231 * Note that nc_ctx->count is NOT updated based on the rounding position
80232 * (it is updated only if carry overflows over the first digit and an
80233 * extra digit is prepended).
80234 */
80235DUK_LOCAL duk_small_int_t duk__dragon4_fixed_format_round(duk__numconv_stringify_ctx *nc_ctx, duk_small_int_t round_idx) {
80236 duk_small_int_t t;
80237 duk_uint8_t *p;
80238 duk_uint8_t roundup_limit;
80239 duk_small_int_t ret = 0;
80240
80241 /*
80242 * round_idx points to the digit which is considered for rounding; the
80243 * digit to its left is the final digit of the rounded value. If round_idx
80244 * is zero, rounding will be performed; the result will either be an empty
80245 * rounded value or if carry happens a '1' digit is generated.
80246 */
80247
80248 if (round_idx >= nc_ctx->count) {
80249 DUK_DDD(DUK_DDDPRINT("round_idx out of bounds (%ld >= %ld (count)) -> no rounding",
80250 (long) round_idx, (long) nc_ctx->count));
80251 return 0;
80252 } else if (round_idx < 0) {
80253 DUK_DDD(DUK_DDDPRINT("round_idx out of bounds (%ld < 0) -> no rounding",
80254 (long) round_idx));
80255 return 0;
80256 }
80257
80258 /*
80259 * Round-up limit.
80260 *
80261 * For even values, divides evenly, e.g. 10 -> roundup_limit=5.
80262 *
80263 * For odd values, rounds up, e.g. 3 -> roundup_limit=2.
80264 * If radix is 3, 0/3 -> down, 1/3 -> down, 2/3 -> up.
80265 */
80266 roundup_limit = (duk_uint8_t) ((nc_ctx->B + 1) / 2);
80267
80268 p = &nc_ctx->digits[round_idx];
80269 if (*p >= roundup_limit) {
80270 DUK_DDD(DUK_DDDPRINT("fixed-format rounding carry required"));
80271 /* carry */
80272 for (;;) {
80273 *p = 0;
80274 if (p == &nc_ctx->digits[0]) {
80275 DUK_DDD(DUK_DDDPRINT("carry propagated to first digit -> special case handling"));
80276 DUK_MEMMOVE((void *) (&nc_ctx->digits[1]),
80277 (const void *) (&nc_ctx->digits[0]),
80278 (size_t) (sizeof(char) * nc_ctx->count));
80279 nc_ctx->digits[0] = 1; /* don't increase 'count' */
80280 nc_ctx->k++; /* position of highest digit changed */
80281 nc_ctx->count++; /* number of digits changed */
80282 ret = 1;
80283 break;
80284 }
80285
80286 DUK_DDD(DUK_DDDPRINT("fixed-format rounding carry: B=%ld, roundup_limit=%ld, p=%p, digits=%p",
80287 (long) nc_ctx->B, (long) roundup_limit, (void *) p, (void *) nc_ctx->digits));
80288 p--;
80289 t = *p;
80290 DUK_DDD(DUK_DDDPRINT("digit before carry: %ld", (long) t));
80291 if (++t < nc_ctx->B) {
80292 DUK_DDD(DUK_DDDPRINT("rounding carry terminated"));
80293 *p = (duk_uint8_t) t;
80294 break;
80295 }
80296
80297 DUK_DDD(DUK_DDDPRINT("wraps, carry to next digit"));
80298 }
80299 }
80300
80301 return ret;
80302}
80303
80304#define DUK__NO_EXP (65536) /* arbitrary marker, outside valid exp range */
80305
80306DUK_LOCAL void duk__dragon4_convert_and_push(duk__numconv_stringify_ctx *nc_ctx,
80307 duk_context *ctx,
80308 duk_small_int_t radix,
80309 duk_small_int_t digits,
80310 duk_small_uint_t flags,
80311 duk_small_int_t neg) {
80312 duk_small_int_t k;
80313 duk_small_int_t pos, pos_end;
80314 duk_small_int_t expt;
80315 duk_small_int_t dig;
80316 duk_uint8_t *q;
80317 duk_uint8_t *buf;
80318
80319 /*
80320 * The string conversion here incorporates all the necessary Ecmascript
80321 * semantics without attempting to be generic. nc_ctx->digits contains
80322 * nc_ctx->count digits (>= 1), with the topmost digit's 'position'
80323 * indicated by nc_ctx->k as follows:
80324 *
80325 * digits="123" count=3 k=0 --> 0.123
80326 * digits="123" count=3 k=1 --> 1.23
80327 * digits="123" count=3 k=5 --> 12300
80328 * digits="123" count=3 k=-1 --> 0.0123
80329 *
80330 * Note that the identifier names used for format selection are different
80331 * in Burger-Dybvig paper and Ecmascript specification (quite confusingly
80332 * so, because e.g. 'k' has a totally different meaning in each). See
80333 * documentation for discussion.
80334 *
80335 * Ecmascript doesn't specify any specific behavior for format selection
80336 * (e.g. when to use exponent notation) for non-base-10 numbers.
80337 *
80338 * The bigint space in the context is reused for string output, as there
80339 * is more than enough space for that (>1kB at the moment), and we avoid
80340 * allocating even more stack.
80341 */
80342
80343 DUK_ASSERT(DUK__NUMCONV_CTX_BIGINTS_SIZE >= DUK__MAX_FORMATTED_LENGTH);
80344 DUK_ASSERT(nc_ctx->count >= 1);
80345
80346 k = nc_ctx->k;
80347 buf = (duk_uint8_t *) &nc_ctx->f; /* XXX: union would be more correct */
80348 q = buf;
80349
80350 /* Exponent handling: if exponent format is used, record exponent value and
80351 * fake k such that one leading digit is generated (e.g. digits=123 -> "1.23").
80352 *
80353 * toFixed() prevents exponent use; otherwise apply a set of criteria to
80354 * match the other API calls (toString(), toPrecision, etc).
80355 */
80356
80357 expt = DUK__NO_EXP;
80358 if (!nc_ctx->abs_pos /* toFixed() */) {
80359 if ((flags & DUK_N2S_FLAG_FORCE_EXP) || /* exponential notation forced */
80360 ((flags & DUK_N2S_FLAG_NO_ZERO_PAD) && /* fixed precision and zero padding would be required */
80361 (k - digits >= 1)) || /* (e.g. k=3, digits=2 -> "12X") */
80362 ((k > 21 || k <= -6) && (radix == 10))) { /* toString() conditions */
80363 DUK_DDD(DUK_DDDPRINT("use exponential notation: k=%ld -> expt=%ld",
80364 (long) k, (long) (k - 1)));
80365 expt = k - 1; /* e.g. 12.3 -> digits="123" k=2 -> 1.23e1 */
80366 k = 1; /* generate mantissa with a single leading whole number digit */
80367 }
80368 }
80369
80370 if (neg) {
80371 *q++ = '-';
80372 }
80373
80374 /* Start position (inclusive) and end position (exclusive) */
80375 pos = (k >= 1 ? k : 1);
80376 if (nc_ctx->is_fixed) {
80377 if (nc_ctx->abs_pos) {
80378 /* toFixed() */
80379 pos_end = -digits;
80380 } else {
80381 pos_end = k - digits;
80382 }
80383 } else {
80384 pos_end = k - nc_ctx->count;
80385 }
80386 if (pos_end > 0) {
80387 pos_end = 0;
80388 }
80389
80390 DUK_DDD(DUK_DDDPRINT("expt=%ld, k=%ld, count=%ld, pos=%ld, pos_end=%ld, is_fixed=%ld, "
80391 "digits=%ld, abs_pos=%ld",
80392 (long) expt, (long) k, (long) nc_ctx->count, (long) pos, (long) pos_end,
80393 (long) nc_ctx->is_fixed, (long) digits, (long) nc_ctx->abs_pos));
80394
80395 /* Digit generation */
80396 while (pos > pos_end) {
80397 DUK_DDD(DUK_DDDPRINT("digit generation: pos=%ld, pos_end=%ld",
80398 (long) pos, (long) pos_end));
80399 if (pos == 0) {
80400 *q++ = (duk_uint8_t) '.';
80401 }
80402 if (pos > k) {
80403 *q++ = (duk_uint8_t) '0';
80404 } else if (pos <= k - nc_ctx->count) {
80405 *q++ = (duk_uint8_t) '0';
80406 } else {
80407 dig = nc_ctx->digits[k - pos];
80408 DUK_ASSERT(dig >= 0 && dig < nc_ctx->B);
80409 *q++ = (duk_uint8_t) DUK__DIGITCHAR(dig);
80410 }
80411
80412 pos--;
80413 }
80414 DUK_ASSERT(pos <= 1);
80415
80416 /* Exponent */
80417 if (expt != DUK__NO_EXP) {
80418 /*
80419 * Exponent notation for non-base-10 numbers isn't specified in Ecmascript
80420 * specification, as it never explicitly turns up: non-decimal numbers can
80421 * only be formatted with Number.prototype.toString([radix]) and for that,
80422 * behavior is not explicitly specified.
80423 *
80424 * Logical choices include formatting the exponent as decimal (e.g. binary
80425 * 100000 as 1e+5) or in current radix (e.g. binary 100000 as 1e+101).
80426 * The Dragon4 algorithm (in the original paper) prints the exponent value
80427 * in the target radix B. However, for radix values 15 and above, the
80428 * exponent separator 'e' is no longer easily parseable. Consider, for
80429 * instance, the number "1.faecee+1c".
80430 */
80431
80432 duk_size_t len;
80433 char expt_sign;
80434
80435 *q++ = 'e';
80436 if (expt >= 0) {
80437 expt_sign = '+';
80438 } else {
80439 expt_sign = '-';
80440 expt = -expt;
80441 }
80442 *q++ = (duk_uint8_t) expt_sign;
80443 len = duk__dragon4_format_uint32(q, (duk_uint32_t) expt, radix);
80444 q += len;
80445 }
80446
80447 duk_push_lstring(ctx, (const char *) buf, (size_t) (q - buf));
80448}
80449
80450/*
80451 * Conversion helpers
80452 */
80453
80454DUK_LOCAL void duk__dragon4_double_to_ctx(duk__numconv_stringify_ctx *nc_ctx, duk_double_t x) {
80456 duk_uint32_t tmp;
80457 duk_small_int_t expt;
80458
80459 /*
80460 * seeeeeee eeeeffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
80461 * A B C D E F G H
80462 *
80463 * s sign bit
80464 * eee... exponent field
80465 * fff... fraction
80466 *
80467 * ieee value = 1.ffff... * 2^(e - 1023) (normal)
80468 * = 0.ffff... * 2^(-1022) (denormal)
80469 *
80470 * algorithm v = f * b^e
80471 */
80472
80473 DUK_DBLUNION_SET_DOUBLE(&u, x);
80474
80475 nc_ctx->f.n = 2;
80476
80477 tmp = DUK_DBLUNION_GET_LOW32(&u);
80478 nc_ctx->f.v[0] = tmp;
80479 tmp = DUK_DBLUNION_GET_HIGH32(&u);
80480 nc_ctx->f.v[1] = tmp & 0x000fffffUL;
80481 expt = (duk_small_int_t) ((tmp >> 20) & 0x07ffUL);
80482
80483 if (expt == 0) {
80484 /* denormal */
80485 expt = DUK__IEEE_DOUBLE_EXP_MIN - 52;
80486 duk__bi_normalize(&nc_ctx->f);
80487 } else {
80488 /* normal: implicit leading 1-bit */
80489 nc_ctx->f.v[1] |= 0x00100000UL;
80490 expt = expt - DUK__IEEE_DOUBLE_EXP_BIAS - 52;
80491 DUK_ASSERT(duk__bi_is_valid(&nc_ctx->f)); /* true, because v[1] has at least one bit set */
80492 }
80493
80494 DUK_ASSERT(duk__bi_is_valid(&nc_ctx->f));
80495
80496 nc_ctx->e = expt;
80497}
80498
80499DUK_LOCAL void duk__dragon4_ctx_to_double(duk__numconv_stringify_ctx *nc_ctx, duk_double_t *x) {
80501 duk_small_int_t expt;
80502 duk_small_int_t i;
80503 duk_small_int_t bitstart;
80504 duk_small_int_t bitround;
80505 duk_small_int_t bitidx;
80506 duk_small_int_t skip_round;
80507 duk_uint32_t t, v;
80508
80509 DUK_ASSERT(nc_ctx->count == 53 + 1);
80510
80511 /* Sometimes this assert is not true right now; it will be true after
80512 * rounding. See: test-bug-numconv-mantissa-assert.js.
80513 */
80514 DUK_ASSERT_DISABLE(nc_ctx->digits[0] == 1); /* zero handled by caller */
80515
80516 /* Should not be required because the code below always sets both high
80517 * and low parts, but at least gcc-4.4.5 fails to deduce this correctly
80518 * (perhaps because the low part is set (seemingly) conditionally in a
80519 * loop), so this is here to avoid the bogus warning.
80520 */
80521 DUK_MEMZERO((void *) &u, sizeof(u));
80522
80523 /*
80524 * Figure out how generated digits match up with the mantissa,
80525 * and then perform rounding. If mantissa overflows, need to
80526 * recompute the exponent (it is bumped and may overflow to
80527 * infinity).
80528 *
80529 * For normal numbers the leading '1' is hidden and ignored,
80530 * and the last bit is used for rounding:
80531 *
80532 * rounding pt
80533 * <--------52------->|
80534 * 1 x x x x ... x x x x|y ==> x x x x ... x x x x
80535 *
80536 * For denormals, the leading '1' is included in the number,
80537 * and the rounding point is different:
80538 *
80539 * rounding pt
80540 * <--52 or less--->|
80541 * 1 x x x x ... x x|x x y ==> 0 0 ... 1 x x ... x x
80542 *
80543 * The largest denormals will have a mantissa beginning with
80544 * a '1' (the explicit leading bit); smaller denormals will
80545 * have leading zero bits.
80546 *
80547 * If the exponent would become too high, the result becomes
80548 * Infinity. If the exponent is so small that the entire
80549 * mantissa becomes zero, the result becomes zero.
80550 *
80551 * Note: the Dragon4 'k' is off-by-one with respect to the IEEE
80552 * exponent. For instance, k==0 indicates that the leading '1'
80553 * digit is at the first binary fraction position (0.1xxx...);
80554 * the corresponding IEEE exponent would be -1.
80555 */
80556
80557 skip_round = 0;
80558
80559 recheck_exp:
80560
80561 expt = nc_ctx->k - 1; /* IEEE exp without bias */
80562 if (expt > 1023) {
80563 /* Infinity */
80564 bitstart = -255; /* needed for inf: causes mantissa to become zero,
80565 * and rounding to be skipped.
80566 */
80567 expt = 2047;
80568 } else if (expt >= -1022) {
80569 /* normal */
80570 bitstart = 1; /* skip leading digit */
80571 expt += DUK__IEEE_DOUBLE_EXP_BIAS;
80572 DUK_ASSERT(expt >= 1 && expt <= 2046);
80573 } else {
80574 /* denormal or zero */
80575 bitstart = 1023 + expt; /* expt==-1023 -> bitstart=0 (leading 1);
80576 * expt==-1024 -> bitstart=-1 (one left of leading 1), etc
80577 */
80578 expt = 0;
80579 }
80580 bitround = bitstart + 52;
80581
80582 DUK_DDD(DUK_DDDPRINT("ieee expt=%ld, bitstart=%ld, bitround=%ld",
80583 (long) expt, (long) bitstart, (long) bitround));
80584
80585 if (!skip_round) {
80586 if (duk__dragon4_fixed_format_round(nc_ctx, bitround)) {
80587 /* Corner case: see test-numconv-parse-mant-carry.js. We could
80588 * just bump the exponent and update bitstart, but it's more robust
80589 * to recompute (but avoid rounding twice).
80590 */
80591 DUK_DDD(DUK_DDDPRINT("rounding caused exponent to be bumped, recheck exponent"));
80592 skip_round = 1;
80593 goto recheck_exp;
80594 }
80595 }
80596
80597 /*
80598 * Create mantissa
80599 */
80600
80601 t = 0;
80602 for (i = 0; i < 52; i++) {
80603 bitidx = bitstart + 52 - 1 - i;
80604 if (bitidx >= nc_ctx->count) {
80605 v = 0;
80606 } else if (bitidx < 0) {
80607 v = 0;
80608 } else {
80609 v = nc_ctx->digits[bitidx];
80610 }
80611 DUK_ASSERT(v == 0 || v == 1);
80612 t += v << (i % 32);
80613 if (i == 31) {
80614 /* low 32 bits is complete */
80615 DUK_DBLUNION_SET_LOW32(&u, t);
80616 t = 0;
80617 }
80618 }
80619 /* t has high mantissa */
80620
80621 DUK_DDD(DUK_DDDPRINT("mantissa is complete: %08lx %08lx",
80622 (unsigned long) t,
80623 (unsigned long) DUK_DBLUNION_GET_LOW32(&u)));
80624
80625 DUK_ASSERT(expt >= 0 && expt <= 0x7ffL);
80626 t += expt << 20;
80627#if 0 /* caller handles sign change */
80628 if (negative) {
80629 t |= 0x80000000U;
80630 }
80631#endif
80632 DUK_DBLUNION_SET_HIGH32(&u, t);
80633
80634 DUK_DDD(DUK_DDDPRINT("number is complete: %08lx %08lx",
80635 (unsigned long) DUK_DBLUNION_GET_HIGH32(&u),
80636 (unsigned long) DUK_DBLUNION_GET_LOW32(&u)));
80637
80638 *x = DUK_DBLUNION_GET_DOUBLE(&u);
80639}
80640
80641/*
80642 * Exposed number-to-string API
80643 *
80644 * Input: [ number ]
80645 * Output: [ string ]
80646 */
80647
80648DUK_INTERNAL void duk_numconv_stringify(duk_context *ctx, duk_small_int_t radix, duk_small_int_t digits, duk_small_uint_t flags) {
80649 duk_double_t x;
80650 duk_small_int_t c;
80651 duk_small_int_t neg;
80652 duk_uint32_t uval;
80653 duk__numconv_stringify_ctx nc_ctx_alloc; /* large context; around 2kB now */
80654 duk__numconv_stringify_ctx *nc_ctx = &nc_ctx_alloc;
80655
80656 x = (duk_double_t) duk_require_number(ctx, -1);
80657 duk_pop(ctx);
80658
80659 /*
80660 * Handle special cases (NaN, infinity, zero).
80661 */
80662
80663 c = (duk_small_int_t) DUK_FPCLASSIFY(x);
80664 if (DUK_SIGNBIT((double) x)) {
80665 x = -x;
80666 neg = 1;
80667 } else {
80668 neg = 0;
80669 }
80670
80671 /* NaN sign bit is platform specific with unpacked, un-normalized NaNs */
80672 DUK_ASSERT(c == DUK_FP_NAN || DUK_SIGNBIT((double) x) == 0);
80673
80674 if (c == DUK_FP_NAN) {
80675 duk_push_hstring_stridx(ctx, DUK_STRIDX_NAN);
80676 return;
80677 } else if (c == DUK_FP_INFINITE) {
80678 if (neg) {
80679 /* -Infinity */
80680 duk_push_hstring_stridx(ctx, DUK_STRIDX_MINUS_INFINITY);
80681 } else {
80682 /* Infinity */
80683 duk_push_hstring_stridx(ctx, DUK_STRIDX_INFINITY);
80684 }
80685 return;
80686 } else if (c == DUK_FP_ZERO) {
80687 /* We can't shortcut zero here if it goes through special formatting
80688 * (such as forced exponential notation).
80689 */
80690 ;
80691 }
80692
80693 /*
80694 * Handle integers in 32-bit range (that is, [-(2**32-1),2**32-1])
80695 * specially, as they're very likely for embedded programs. This
80696 * is now done for all radix values. We must be careful not to use
80697 * the fast path when special formatting (e.g. forced exponential)
80698 * is in force.
80699 *
80700 * XXX: could save space by supporting radix 10 only and using
80701 * sprintf "%lu" for the fast path and for exponent formatting.
80702 */
80703
80704 uval = (unsigned int) x;
80705 if (((double) uval) == x && /* integer number in range */
80706 flags == 0) { /* no special formatting */
80707 /* use bigint area as a temp */
80708 duk_uint8_t *buf = (duk_uint8_t *) (&nc_ctx->f);
80709 duk_uint8_t *p = buf;
80710
80711 DUK_ASSERT(DUK__NUMCONV_CTX_BIGINTS_SIZE >= 32 + 1); /* max size: radix=2 + sign */
80712 if (neg && uval != 0) {
80713 /* no negative sign for zero */
80714 *p++ = (duk_uint8_t) '-';
80715 }
80716 p += duk__dragon4_format_uint32(p, uval, radix);
80717 duk_push_lstring(ctx, (const char *) buf, (duk_size_t) (p - buf));
80718 return;
80719 }
80720
80721 /*
80722 * Dragon4 setup.
80723 *
80724 * Convert double from IEEE representation for conversion;
80725 * normal finite values have an implicit leading 1-bit. The
80726 * slow path algorithm doesn't handle zero, so zero is special
80727 * cased here but still creates a valid nc_ctx, and goes
80728 * through normal formatting in case special formatting has
80729 * been requested (e.g. forced exponential format: 0 -> "0e+0").
80730 */
80731
80732 /* Would be nice to bulk clear the allocation, but the context
80733 * is 1-2 kilobytes and nothing should rely on it being zeroed.
80734 */
80735#if 0
80736 DUK_MEMZERO((void *) nc_ctx, sizeof(*nc_ctx)); /* slow init, do only for slow path cases */
80737#endif
80738
80739 nc_ctx->is_s2n = 0;
80740 nc_ctx->b = 2;
80741 nc_ctx->B = radix;
80742 nc_ctx->abs_pos = 0;
80743 if (flags & DUK_N2S_FLAG_FIXED_FORMAT) {
80744 nc_ctx->is_fixed = 1;
80745 if (flags & DUK_N2S_FLAG_FRACTION_DIGITS) {
80746 /* absolute req_digits; e.g. digits = 1 -> last digit is 0,
80747 * but add an extra digit for rounding.
80748 */
80749 nc_ctx->abs_pos = 1;
80750 nc_ctx->req_digits = (-digits + 1) - 1;
80751 } else {
80752 nc_ctx->req_digits = digits + 1;
80753 }
80754 } else {
80755 nc_ctx->is_fixed = 0;
80756 nc_ctx->req_digits = 0;
80757 }
80758
80759 if (c == DUK_FP_ZERO) {
80760 /* Zero special case: fake requested number of zero digits; ensure
80761 * no sign bit is printed. Relative and absolute fixed format
80762 * require separate handling.
80763 */
80764 duk_small_int_t count;
80765 if (nc_ctx->is_fixed) {
80766 if (nc_ctx->abs_pos) {
80767 count = digits + 2; /* lead zero + 'digits' fractions + 1 for rounding */
80768 } else {
80769 count = digits + 1; /* + 1 for rounding */
80770 }
80771 } else {
80772 count = 1;
80773 }
80774 DUK_DDD(DUK_DDDPRINT("count=%ld", (long) count));
80775 DUK_ASSERT(count >= 1);
80776 DUK_MEMZERO((void *) nc_ctx->digits, count);
80777 nc_ctx->count = count;
80778 nc_ctx->k = 1; /* 0.000... */
80779 neg = 0;
80780 goto zero_skip;
80781 }
80782
80783 duk__dragon4_double_to_ctx(nc_ctx, x); /* -> sets 'f' and 'e' */
80784 DUK__BI_PRINT("f", &nc_ctx->f);
80785 DUK_DDD(DUK_DDDPRINT("e=%ld", (long) nc_ctx->e));
80786
80787 /*
80788 * Dragon4 slow path digit generation.
80789 */
80790
80791 duk__dragon4_prepare(nc_ctx); /* setup many variables in nc_ctx */
80792
80793 DUK_DDD(DUK_DDDPRINT("after prepare:"));
80794 DUK__BI_PRINT("r", &nc_ctx->r);
80795 DUK__BI_PRINT("s", &nc_ctx->s);
80796 DUK__BI_PRINT("mp", &nc_ctx->mp);
80797 DUK__BI_PRINT("mm", &nc_ctx->mm);
80798
80799 duk__dragon4_scale(nc_ctx);
80800
80801 DUK_DDD(DUK_DDDPRINT("after scale; k=%ld", (long) nc_ctx->k));
80802 DUK__BI_PRINT("r", &nc_ctx->r);
80803 DUK__BI_PRINT("s", &nc_ctx->s);
80804 DUK__BI_PRINT("mp", &nc_ctx->mp);
80805 DUK__BI_PRINT("mm", &nc_ctx->mm);
80806
80807 duk__dragon4_generate(nc_ctx);
80808
80809 /*
80810 * Convert and push final string.
80811 */
80812
80813 zero_skip:
80814
80815 if (flags & DUK_N2S_FLAG_FIXED_FORMAT) {
80816 /* Perform fixed-format rounding. */
80817 duk_small_int_t roundpos;
80818 if (flags & DUK_N2S_FLAG_FRACTION_DIGITS) {
80819 /* 'roundpos' is relative to nc_ctx->k and increases to the right
80820 * (opposite of how 'k' changes).
80821 */
80822 roundpos = -digits; /* absolute position for digit considered for rounding */
80823 roundpos = nc_ctx->k - roundpos;
80824 } else {
80825 roundpos = digits;
80826 }
80827 DUK_DDD(DUK_DDDPRINT("rounding: k=%ld, count=%ld, digits=%ld, roundpos=%ld",
80828 (long) nc_ctx->k, (long) nc_ctx->count, (long) digits, (long) roundpos));
80829 (void) duk__dragon4_fixed_format_round(nc_ctx, roundpos);
80830
80831 /* Note: 'count' is currently not adjusted by rounding (i.e. the
80832 * digits are not "chopped off". That shouldn't matter because
80833 * the digit position (absolute or relative) is passed on to the
80834 * convert-and-push function.
80835 */
80836 }
80837
80838 duk__dragon4_convert_and_push(nc_ctx, ctx, radix, digits, flags, neg);
80839}
80840
80841/*
80842 * Exposed string-to-number API
80843 *
80844 * Input: [ string ]
80845 * Output: [ number ]
80846 *
80847 * If number parsing fails, a NaN is pushed as the result. If number parsing
80848 * fails due to an internal error, an InternalError is thrown.
80849 */
80850
80851DUK_INTERNAL void duk_numconv_parse(duk_context *ctx, duk_small_int_t radix, duk_small_uint_t flags) {
80852 duk_hthread *thr = (duk_hthread *) ctx;
80853 duk__numconv_stringify_ctx nc_ctx_alloc; /* large context; around 2kB now */
80854 duk__numconv_stringify_ctx *nc_ctx = &nc_ctx_alloc;
80855 duk_double_t res;
80856 duk_hstring *h_str;
80857 duk_small_int_t expt;
80858 duk_small_int_t expt_neg;
80859 duk_small_int_t expt_adj;
80860 duk_small_int_t neg;
80861 duk_small_int_t dig;
80862 duk_small_int_t dig_whole;
80863 duk_small_int_t dig_lzero;
80864 duk_small_int_t dig_frac;
80865 duk_small_int_t dig_expt;
80866 duk_small_int_t dig_prec;
80867 const duk__exp_limits *explim;
80868 const duk_uint8_t *p;
80869 duk_small_int_t ch;
80870
80871 DUK_DDD(DUK_DDDPRINT("parse number: %!T, radix=%ld, flags=0x%08lx",
80872 (duk_tval *) duk_get_tval(ctx, -1),
80873 (long) radix, (unsigned long) flags));
80874
80875 DUK_ASSERT(radix >= 2 && radix <= 36);
80876 DUK_ASSERT(radix - 2 < (duk_small_int_t) sizeof(duk__str2num_digits_for_radix));
80877
80878 /*
80879 * Preliminaries: trim, sign, Infinity check
80880 *
80881 * We rely on the interned string having a NUL terminator, which will
80882 * cause a parse failure wherever it is encountered. As a result, we
80883 * don't need separate pointer checks.
80884 *
80885 * There is no special parsing for 'NaN' in the specification although
80886 * 'Infinity' (with an optional sign) is allowed in some contexts.
80887 * Some contexts allow plus/minus sign, while others only allow the
80888 * minus sign (like JSON.parse()).
80889 *
80890 * Automatic hex number detection (leading '0x' or '0X') and octal
80891 * number detection (leading '0' followed by at least one octal digit)
80892 * is done here too.
80893 *
80894 * Symbols are not explicitly rejected here (that's up to the caller).
80895 * If a symbol were passed here, it should ultimately safely fail
80896 * parsing due to a syntax error.
80897 */
80898
80899 if (flags & DUK_S2N_FLAG_TRIM_WHITE) {
80900 /* Leading / trailing whitespace is sometimes accepted and
80901 * sometimes not. After white space trimming, all valid input
80902 * characters are pure ASCII.
80903 */
80904 duk_trim(ctx, -1);
80905 }
80906 h_str = duk_require_hstring(ctx, -1);
80907 DUK_ASSERT(h_str != NULL);
80908 p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_str);
80909
80910 neg = 0;
80911 ch = *p;
80912 if (ch == (duk_small_int_t) '+') {
80913 if ((flags & DUK_S2N_FLAG_ALLOW_PLUS) == 0) {
80914 DUK_DDD(DUK_DDDPRINT("parse failed: leading plus sign not allowed"));
80915 goto parse_fail;
80916 }
80917 p++;
80918 } else if (ch == (duk_small_int_t) '-') {
80919 if ((flags & DUK_S2N_FLAG_ALLOW_MINUS) == 0) {
80920 DUK_DDD(DUK_DDDPRINT("parse failed: leading minus sign not allowed"));
80921 goto parse_fail;
80922 }
80923 p++;
80924 neg = 1;
80925 }
80926
80927 if ((flags & DUK_S2N_FLAG_ALLOW_INF) && DUK_STRNCMP((const char *) p, "Infinity", 8) == 0) {
80928 /* Don't check for Infinity unless the context allows it.
80929 * 'Infinity' is a valid integer literal in e.g. base-36:
80930 *
80931 * parseInt('Infinity', 36)
80932 * 1461559270678
80933 */
80934
80935 if ((flags & DUK_S2N_FLAG_ALLOW_GARBAGE) == 0 && p[8] != DUK_ASC_NUL) {
80936 DUK_DDD(DUK_DDDPRINT("parse failed: trailing garbage after matching 'Infinity' not allowed"));
80937 goto parse_fail;
80938 } else {
80939 res = DUK_DOUBLE_INFINITY;
80940 goto negcheck_and_ret;
80941 }
80942 }
80943 ch = *p;
80944 if (ch == (duk_small_int_t) '0') {
80945 duk_small_int_t detect_radix = 0;
80946 ch = DUK_LOWERCASE_CHAR_ASCII(p[1]); /* 'x' or 'X' -> 'x' */
80947 if ((flags & DUK_S2N_FLAG_ALLOW_AUTO_HEX_INT) && ch == DUK_ASC_LC_X) {
80948 DUK_DDD(DUK_DDDPRINT("detected 0x/0X hex prefix, changing radix and preventing fractions and exponent"));
80949 detect_radix = 16;
80950#if 0
80951 } else if ((flags & DUK_S2N_FLAG_ALLOW_AUTO_LEGACY_OCT_INT) &&
80952 (ch >= (duk_small_int_t) '0' && ch <= (duk_small_int_t) '9')) {
80953 DUK_DDD(DUK_DDDPRINT("detected 0n oct prefix, changing radix and preventing fractions and exponent"));
80954 detect_radix = 8;
80955
80956 /* NOTE: if this legacy octal case is added back, it has
80957 * different flags and 'p' advance so this needs to be
80958 * reworked.
80959 */
80960 flags |= DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO; /* interpret e.g. '09' as '0', not NaN */
80961 p += 1;
80962#endif
80963 } else if ((flags & DUK_S2N_FLAG_ALLOW_AUTO_OCT_INT) && ch == DUK_ASC_LC_O) {
80964 DUK_DDD(DUK_DDDPRINT("detected 0o oct prefix, changing radix and preventing fractions and exponent"));
80965 detect_radix = 8;
80966 } else if ((flags & DUK_S2N_FLAG_ALLOW_AUTO_BIN_INT) && ch == DUK_ASC_LC_B) {
80967 DUK_DDD(DUK_DDDPRINT("detected 0b bin prefix, changing radix and preventing fractions and exponent"));
80968 detect_radix = 2;
80969 }
80970 if (detect_radix > 0) {
80971 radix = detect_radix;
80972 /* Clear empty as zero flag: interpret e.g. '0x' and '0xg' as a NaN (= parse error) */
80973 flags &= ~(DUK_S2N_FLAG_ALLOW_EXP | DUK_S2N_FLAG_ALLOW_EMPTY_FRAC |
80974 DUK_S2N_FLAG_ALLOW_FRAC | DUK_S2N_FLAG_ALLOW_NAKED_FRAC |
80975 DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO);
80976 flags |= DUK_S2N_FLAG_ALLOW_LEADING_ZERO; /* allow e.g. '0x0009' and '0b00010001' */
80977 p += 2;
80978 }
80979 }
80980
80981 /*
80982 * Scan number and setup for Dragon4.
80983 *
80984 * The fast path case is detected during setup: an integer which
80985 * can be converted without rounding, no net exponent. The fast
80986 * path could be implemented as a separate scan, but may not really
80987 * be worth it: the multiplications for building 'f' are not
80988 * expensive when 'f' is small.
80989 *
80990 * The significand ('f') must contain enough bits of (apparent)
80991 * accuracy, so that Dragon4 will generate enough binary output digits.
80992 * For decimal numbers, this means generating a 20-digit significand,
80993 * which should yield enough practical accuracy to parse IEEE doubles.
80994 * In fact, the Ecmascript specification explicitly allows an
80995 * implementation to treat digits beyond 20 as zeroes (and even
80996 * to round the 20th digit upwards). For non-decimal numbers, the
80997 * appropriate number of digits has been precomputed for comparable
80998 * accuracy.
80999 *
81000 * Digit counts:
81001 *
81002 * [ dig_lzero ]
81003 * |
81004 * .+-..---[ dig_prec ]----.
81005 * | || |
81006 * 0000123.456789012345678901234567890e+123456
81007 * | | | | | |
81008 * `--+--' `------[ dig_frac ]-------' `-+--'
81009 * | |
81010 * [ dig_whole ] [ dig_expt ]
81011 *
81012 * dig_frac and dig_expt are -1 if not present
81013 * dig_lzero is only computed for whole number part
81014 *
81015 * Parsing state
81016 *
81017 * Parsing whole part dig_frac < 0 AND dig_expt < 0
81018 * Parsing fraction part dig_frac >= 0 AND dig_expt < 0
81019 * Parsing exponent part dig_expt >= 0 (dig_frac may be < 0 or >= 0)
81020 *
81021 * Note: in case we hit an implementation limit (like exponent range),
81022 * we should throw an error, NOT return NaN or Infinity. Even with
81023 * very large exponent (or significand) values the final result may be
81024 * finite, so NaN/Infinity would be incorrect.
81025 */
81026
81027 duk__bi_set_small(&nc_ctx->f, 0);
81028 dig_prec = 0;
81029 dig_lzero = 0;
81030 dig_whole = 0;
81031 dig_frac = -1;
81032 dig_expt = -1;
81033 expt = 0;
81034 expt_adj = 0; /* essentially tracks digit position of lowest 'f' digit */
81035 expt_neg = 0;
81036 for (;;) {
81037 ch = *p++;
81038
81039 DUK_DDD(DUK_DDDPRINT("parse digits: p=%p, ch='%c' (%ld), expt=%ld, expt_adj=%ld, "
81040 "dig_whole=%ld, dig_frac=%ld, dig_expt=%ld, dig_lzero=%ld, dig_prec=%ld",
81041 (const void *) p, (int) ((ch >= 0x20 && ch <= 0x7e) ? ch : '?'), (long) ch,
81042 (long) expt, (long) expt_adj, (long) dig_whole, (long) dig_frac,
81043 (long) dig_expt, (long) dig_lzero, (long) dig_prec));
81044 DUK__BI_PRINT("f", &nc_ctx->f);
81045
81046 /* Most common cases first. */
81047 if (ch >= (duk_small_int_t) '0' && ch <= (duk_small_int_t) '9') {
81048 dig = (duk_small_int_t) ch - '0' + 0;
81049 } else if (ch == (duk_small_int_t) '.') {
81050 /* A leading digit is not required in some cases, e.g. accept ".123".
81051 * In other cases (JSON.parse()) a leading digit is required. This
81052 * is checked for after the loop.
81053 */
81054 if (dig_frac >= 0 || dig_expt >= 0) {
81055 if (flags & DUK_S2N_FLAG_ALLOW_GARBAGE) {
81056 DUK_DDD(DUK_DDDPRINT("garbage termination (invalid period)"));
81057 break;
81058 } else {
81059 DUK_DDD(DUK_DDDPRINT("parse failed: period not allowed"));
81060 goto parse_fail;
81061 }
81062 }
81063
81064 if ((flags & DUK_S2N_FLAG_ALLOW_FRAC) == 0) {
81065 /* Some contexts don't allow fractions at all; this can't be a
81066 * post-check because the state ('f' and expt) would be incorrect.
81067 */
81068 if (flags & DUK_S2N_FLAG_ALLOW_GARBAGE) {
81069 DUK_DDD(DUK_DDDPRINT("garbage termination (invalid first period)"));
81070 break;
81071 } else {
81072 DUK_DDD(DUK_DDDPRINT("parse failed: fraction part not allowed"));
81073 }
81074 }
81075
81076 DUK_DDD(DUK_DDDPRINT("start fraction part"));
81077 dig_frac = 0;
81078 continue;
81079 } else if (ch == (duk_small_int_t) 0) {
81080 DUK_DDD(DUK_DDDPRINT("NUL termination"));
81081 break;
81082 } else if ((flags & DUK_S2N_FLAG_ALLOW_EXP) &&
81083 dig_expt < 0 && (ch == (duk_small_int_t) 'e' || ch == (duk_small_int_t) 'E')) {
81084 /* Note: we don't parse back exponent notation for anything else
81085 * than radix 10, so this is not an ambiguous check (e.g. hex
81086 * exponent values may have 'e' either as a significand digit
81087 * or as an exponent separator).
81088 *
81089 * If the exponent separator occurs twice, 'e' will be interpreted
81090 * as a digit (= 14) and will be rejected as an invalid decimal
81091 * digit.
81092 */
81093
81094 DUK_DDD(DUK_DDDPRINT("start exponent part"));
81095
81096 /* Exponent without a sign or with a +/- sign is accepted
81097 * by all call sites (even JSON.parse()).
81098 */
81099 ch = *p;
81100 if (ch == (duk_small_int_t) '-') {
81101 expt_neg = 1;
81102 p++;
81103 } else if (ch == (duk_small_int_t) '+') {
81104 p++;
81105 }
81106 dig_expt = 0;
81107 continue;
81108 } else if (ch >= (duk_small_int_t) 'a' && ch <= (duk_small_int_t) 'z') {
81109 dig = (duk_small_int_t) (ch - (duk_small_int_t) 'a' + 0x0a);
81110 } else if (ch >= (duk_small_int_t) 'A' && ch <= (duk_small_int_t) 'Z') {
81111 dig = (duk_small_int_t) (ch - (duk_small_int_t) 'A' + 0x0a);
81112 } else {
81113 dig = 255; /* triggers garbage digit check below */
81114 }
81115 DUK_ASSERT((dig >= 0 && dig <= 35) || dig == 255);
81116
81117 if (dig >= radix) {
81118 if (flags & DUK_S2N_FLAG_ALLOW_GARBAGE) {
81119 DUK_DDD(DUK_DDDPRINT("garbage termination"));
81120 break;
81121 } else {
81122 DUK_DDD(DUK_DDDPRINT("parse failed: trailing garbage or invalid digit"));
81123 goto parse_fail;
81124 }
81125 }
81126
81127 if (dig_expt < 0) {
81128 /* whole or fraction digit */
81129
81130 if (dig_prec < duk__str2num_digits_for_radix[radix - 2]) {
81131 /* significant from precision perspective */
81132
81133 duk_small_int_t f_zero = duk__bi_is_zero(&nc_ctx->f);
81134 if (f_zero && dig == 0) {
81135 /* Leading zero is not counted towards precision digits; not
81136 * in the integer part, nor in the fraction part.
81137 */
81138 if (dig_frac < 0) {
81139 dig_lzero++;
81140 }
81141 } else {
81142 /* XXX: join these ops (multiply-accumulate), but only if
81143 * code footprint decreases.
81144 */
81145 duk__bi_mul_small(&nc_ctx->t1, &nc_ctx->f, radix);
81146 duk__bi_add_small(&nc_ctx->f, &nc_ctx->t1, dig);
81147 dig_prec++;
81148 }
81149 } else {
81150 /* Ignore digits beyond a radix-specific limit, but note them
81151 * in expt_adj.
81152 */
81153 expt_adj++;
81154 }
81155
81156 if (dig_frac >= 0) {
81157 dig_frac++;
81158 expt_adj--;
81159 } else {
81160 dig_whole++;
81161 }
81162 } else {
81163 /* exponent digit */
81164
81165 expt = expt * radix + dig;
81166 if (expt > DUK_S2N_MAX_EXPONENT) {
81167 /* impose a reasonable exponent limit, so that exp
81168 * doesn't need to get tracked using a bigint.
81169 */
81170 DUK_DDD(DUK_DDDPRINT("parse failed: exponent too large"));
81171 goto parse_explimit_error;
81172 }
81173 dig_expt++;
81174 }
81175 }
81176
81177 /* Leading zero. */
81178
81179 if (dig_lzero > 0 && dig_whole > 1) {
81180 if ((flags & DUK_S2N_FLAG_ALLOW_LEADING_ZERO) == 0) {
81181 DUK_DDD(DUK_DDDPRINT("parse failed: leading zeroes not allowed in integer part"));
81182 goto parse_fail;
81183 }
81184 }
81185
81186 /* Validity checks for various fraction formats ("0.1", ".1", "1.", "."). */
81187
81188 if (dig_whole == 0) {
81189 if (dig_frac == 0) {
81190 /* "." is not accepted in any format */
81191 DUK_DDD(DUK_DDDPRINT("parse failed: plain period without leading or trailing digits"));
81192 goto parse_fail;
81193 } else if (dig_frac > 0) {
81194 /* ".123" */
81195 if ((flags & DUK_S2N_FLAG_ALLOW_NAKED_FRAC) == 0) {
81196 DUK_DDD(DUK_DDDPRINT("parse failed: fraction part not allowed without "
81197 "leading integer digit(s)"));
81198 goto parse_fail;
81199 }
81200 } else {
81201 /* empty ("") is allowed in some formats (e.g. Number(''), as zero */
81202 if ((flags & DUK_S2N_FLAG_ALLOW_EMPTY_AS_ZERO) == 0) {
81203 DUK_DDD(DUK_DDDPRINT("parse failed: empty string not allowed (as zero)"));
81204 goto parse_fail;
81205 }
81206 }
81207 } else {
81208 if (dig_frac == 0) {
81209 /* "123." is allowed in some formats */
81210 if ((flags & DUK_S2N_FLAG_ALLOW_EMPTY_FRAC) == 0) {
81211 DUK_DDD(DUK_DDDPRINT("parse failed: empty fractions"));
81212 goto parse_fail;
81213 }
81214 } else if (dig_frac > 0) {
81215 /* "123.456" */
81216 ;
81217 } else {
81218 /* "123" */
81219 ;
81220 }
81221 }
81222
81223 /* Exponent without digits (e.g. "1e" or "1e+"). If trailing garbage is
81224 * allowed, ignore exponent part as garbage (= parse as "1", i.e. exp 0).
81225 */
81226
81227 if (dig_expt == 0) {
81228 if ((flags & DUK_S2N_FLAG_ALLOW_GARBAGE) == 0) {
81229 DUK_DDD(DUK_DDDPRINT("parse failed: empty exponent"));
81230 goto parse_fail;
81231 }
81232 DUK_ASSERT(expt == 0);
81233 }
81234
81235 if (expt_neg) {
81236 expt = -expt;
81237 }
81238 DUK_DDD(DUK_DDDPRINT("expt=%ld, expt_adj=%ld, net exponent -> %ld",
81239 (long) expt, (long) expt_adj, (long) (expt + expt_adj)));
81240 expt += expt_adj;
81241
81242 /* Fast path check. */
81243
81244 if (nc_ctx->f.n <= 1 && /* 32-bit value */
81245 expt == 0 /* no net exponent */) {
81246 /* Fast path is triggered for no exponent and also for balanced exponent
81247 * and fraction parts, e.g. for "1.23e2" == "123". Remember to respect
81248 * zero sign.
81249 */
81250
81251 /* XXX: could accept numbers larger than 32 bits, e.g. up to 53 bits? */
81252 DUK_DDD(DUK_DDDPRINT("fast path number parse"));
81253 if (nc_ctx->f.n == 1) {
81254 res = (double) nc_ctx->f.v[0];
81255 } else {
81256 res = 0.0;
81257 }
81258 goto negcheck_and_ret;
81259 }
81260
81261 /* Significand ('f') padding. */
81262
81263 while (dig_prec < duk__str2num_digits_for_radix[radix - 2]) {
81264 /* Pad significand with "virtual" zero digits so that Dragon4 will
81265 * have enough (apparent) precision to work with.
81266 */
81267 DUK_DDD(DUK_DDDPRINT("dig_prec=%ld, pad significand with zero", (long) dig_prec));
81268 duk__bi_mul_small_copy(&nc_ctx->f, radix, &nc_ctx->t1);
81269 DUK__BI_PRINT("f", &nc_ctx->f);
81270 expt--;
81271 dig_prec++;
81272 }
81273
81274 DUK_DDD(DUK_DDDPRINT("final exponent: %ld", (long) expt));
81275
81276 /* Detect zero special case. */
81277
81278 if (nc_ctx->f.n == 0) {
81279 /* This may happen even after the fast path check, if exponent is
81280 * not balanced (e.g. "0e1"). Remember to respect zero sign.
81281 */
81282 DUK_DDD(DUK_DDDPRINT("significand is zero"));
81283 res = 0.0;
81284 goto negcheck_and_ret;
81285 }
81286
81287
81288 /* Quick reject of too large or too small exponents. This check
81289 * would be incorrect for zero (e.g. "0e1000" is zero, not Infinity)
81290 * so zero check must be above.
81291 */
81292
81293 explim = &duk__str2num_exp_limits[radix - 2];
81294 if (expt > explim->upper) {
81295 DUK_DDD(DUK_DDDPRINT("exponent too large -> infinite"));
81296 res = (duk_double_t) DUK_DOUBLE_INFINITY;
81297 goto negcheck_and_ret;
81298 } else if (expt < explim->lower) {
81299 DUK_DDD(DUK_DDDPRINT("exponent too small -> zero"));
81300 res = (duk_double_t) 0.0;
81301 goto negcheck_and_ret;
81302 }
81303
81304 nc_ctx->is_s2n = 1;
81305 nc_ctx->e = expt;
81306 nc_ctx->b = radix;
81307 nc_ctx->B = 2;
81308 nc_ctx->is_fixed = 1;
81309 nc_ctx->abs_pos = 0;
81310 nc_ctx->req_digits = 53 + 1;
81311
81312 DUK__BI_PRINT("f", &nc_ctx->f);
81313 DUK_DDD(DUK_DDDPRINT("e=%ld", (long) nc_ctx->e));
81314
81315 /*
81316 * Dragon4 slow path (binary) digit generation.
81317 * An extra digit is generated for rounding.
81318 */
81319
81320 duk__dragon4_prepare(nc_ctx); /* setup many variables in nc_ctx */
81321
81322 DUK_DDD(DUK_DDDPRINT("after prepare:"));
81323 DUK__BI_PRINT("r", &nc_ctx->r);
81324 DUK__BI_PRINT("s", &nc_ctx->s);
81325 DUK__BI_PRINT("mp", &nc_ctx->mp);
81326 DUK__BI_PRINT("mm", &nc_ctx->mm);
81327
81328 duk__dragon4_scale(nc_ctx);
81329
81330 DUK_DDD(DUK_DDDPRINT("after scale; k=%ld", (long) nc_ctx->k));
81331 DUK__BI_PRINT("r", &nc_ctx->r);
81332 DUK__BI_PRINT("s", &nc_ctx->s);
81333 DUK__BI_PRINT("mp", &nc_ctx->mp);
81334 DUK__BI_PRINT("mm", &nc_ctx->mm);
81335
81336 duk__dragon4_generate(nc_ctx);
81337
81338 DUK_ASSERT(nc_ctx->count == 53 + 1);
81339
81340 /*
81341 * Convert binary digits into an IEEE double. Need to handle
81342 * denormals and rounding correctly.
81343 *
81344 * Some call sites currently assume the result is always a
81345 * non-fastint double. If this is changed, check all call
81346 * sites.
81347 */
81348
81349 duk__dragon4_ctx_to_double(nc_ctx, &res);
81350 goto negcheck_and_ret;
81351
81352 negcheck_and_ret:
81353 if (neg) {
81354 res = -res;
81355 }
81356 duk_pop(ctx);
81357 duk_push_number(ctx, (double) res);
81358 DUK_DDD(DUK_DDDPRINT("result: %!T", (duk_tval *) duk_get_tval(ctx, -1)));
81359 return;
81360
81361 parse_fail:
81362 DUK_DDD(DUK_DDDPRINT("parse failed"));
81363 duk_pop(ctx);
81364 duk_push_nan(ctx);
81365 return;
81366
81367 parse_explimit_error:
81368 DUK_DDD(DUK_DDDPRINT("parse failed, internal error, can't return a value"));
81369 DUK_ERROR_RANGE(thr, "exponent too large");
81370 return;
81371}
81372
81373/* automatic undefs */
81374#undef DUK__BI_MAX_PARTS
81375#undef DUK__BI_PRINT
81376#undef DUK__DIGITCHAR
81377#undef DUK__DRAGON4_OUTPUT_PREINC
81378#undef DUK__IEEE_DOUBLE_EXP_BIAS
81379#undef DUK__IEEE_DOUBLE_EXP_MIN
81380#undef DUK__MAX_FORMATTED_LENGTH
81381#undef DUK__MAX_OUTPUT_DIGITS
81382#undef DUK__NO_EXP
81383#undef DUK__NUMCONV_CTX_BIGINTS_SIZE
81384#undef DUK__NUMCONV_CTX_NUM_BIGINTS
81385/*
81386 * Regexp compilation.
81387 *
81388 * See doc/regexp.rst for a discussion of the compilation approach and
81389 * current limitations.
81391 * Regexp bytecode assumes jumps can be expressed with signed 32-bit
81392 * integers. Consequently the bytecode size must not exceed 0x7fffffffL.
81393 * The implementation casts duk_size_t (buffer size) to duk_(u)int32_t
81394 * in many places. Although this could be changed, the bytecode format
81395 * limit would still prevent regexps exceeding the signed 32-bit limit
81396 * from working.
81397 *
81398 * XXX: The implementation does not prevent bytecode from exceeding the
81399 * maximum supported size. This could be done by limiting the maximum
81400 * input string size (assuming an upper bound can be computed for number
81401 * of bytecode bytes emitted per input byte) or checking buffer maximum
81402 * size when emitting bytecode (slower).
81403 */
81404
81405/* #include duk_internal.h -> already included */
81406
81407#if defined(DUK_USE_REGEXP_SUPPORT)
81408
81409/*
81410 * Helper macros
81411 */
81412
81413#define DUK__RE_INITIAL_BUFSIZE 64
81414
81415#define DUK__RE_BUFLEN(re_ctx) \
81416 DUK_BW_GET_SIZE(re_ctx->thr, &re_ctx->bw)
81417
81418/*
81419 * Disjunction struct: result of parsing a disjunction
81420 */
81421
81422typedef struct {
81423 /* Number of characters that the atom matches (e.g. 3 for 'abc'),
81424 * -1 if atom is complex and number of matched characters either
81425 * varies or is not known.
81426 */
81427 duk_int32_t charlen;
81428
81429#if 0
81430 /* These are not needed to implement quantifier capture handling,
81431 * but might be needed at some point.
81432 */
81433
81434 /* re_ctx->captures at start and end of atom parsing.
81435 * Since 'captures' indicates highest capture number emitted
81436 * so far in a DUK_REOP_SAVE, the captures numbers saved by
81437 * the atom are: ]start_captures,end_captures].
81438 */
81439 duk_uint32_t start_captures;
81440 duk_uint32_t end_captures;
81441#endif
81443
81444/*
81445 * Encoding helpers
81446 *
81447 * Some of the typing is bytecode based, e.g. slice sizes are unsigned 32-bit
81448 * even though the buffer operations will use duk_size_t.
81449 */
81450
81451/* XXX: the insert helpers should ensure that the bytecode result is not
81452 * larger than expected (or at least assert for it). Many things in the
81453 * bytecode, like skip offsets, won't work correctly if the bytecode is
81454 * larger than say 2G.
81455 */
81456
81457DUK_LOCAL duk_uint32_t duk__encode_i32(duk_int32_t x) {
81458 if (x < 0) {
81459 return ((duk_uint32_t) (-x)) * 2 + 1;
81460 } else {
81461 return ((duk_uint32_t) x) * 2;
81462 }
81463}
81464
81465/* XXX: return type should probably be duk_size_t, or explicit checks are needed for
81466 * maximum size.
81467 */
81468DUK_LOCAL duk_uint32_t duk__insert_u32(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_uint32_t x) {
81469 duk_uint8_t buf[DUK_UNICODE_MAX_XUTF8_LENGTH];
81470 duk_small_int_t len;
81471
81472 len = duk_unicode_encode_xutf8((duk_ucodepoint_t) x, buf);
81473 DUK_BW_INSERT_ENSURE_BYTES(re_ctx->thr, &re_ctx->bw, offset, buf, len);
81474 return (duk_uint32_t) len;
81475}
81476
81477DUK_LOCAL void duk__append_u32(duk_re_compiler_ctx *re_ctx, duk_uint32_t x) {
81478 DUK_BW_WRITE_ENSURE_XUTF8(re_ctx->thr, &re_ctx->bw, x);
81479}
81480
81481DUK_LOCAL void duk__append_7bit(duk_re_compiler_ctx *re_ctx, duk_uint32_t x) {
81482#if defined(DUK_USE_PREFER_SIZE)
81483 duk__append_u32(re_ctx, x);
81484#else
81485 DUK_ASSERT(x <= 0x7fU);
81486 DUK_BW_WRITE_ENSURE_U8(re_ctx->thr, &re_ctx->bw, (duk_uint8_t) x);
81487#endif
81488}
81489
81490#if 0
81491DUK_LOCAL void duk__append_2bytes(duk_re_compiler_ctx *re_ctx, duk_uint8_t x, duk_uint8_t y) {
81492 DUK_BW_WRITE_ENSURE_U8_2(re_ctx->thr, &re_ctx->bw, x, y);
81493}
81494#endif
81495
81496DUK_LOCAL duk_uint32_t duk__insert_i32(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_int32_t x) {
81497 return duk__insert_u32(re_ctx, offset, duk__encode_i32(x));
81498}
81499
81500DUK_LOCAL void duk__append_reop(duk_re_compiler_ctx *re_ctx, duk_uint32_t reop) {
81501 DUK_ASSERT(reop <= 0x7fU);
81502 (void) duk__append_7bit(re_ctx, reop);
81503}
81504
81505#if 0 /* unused */
81506DUK_LOCAL void duk__append_i32(duk_re_compiler_ctx *re_ctx, duk_int32_t x) {
81507 duk__append_u32(re_ctx, duk__encode_i32(x));
81508}
81509#endif
81510
81511/* special helper for emitting u16 lists (used for character ranges for built-in char classes) */
81512DUK_LOCAL void duk__append_u16_list(duk_re_compiler_ctx *re_ctx, const duk_uint16_t *values, duk_uint32_t count) {
81513 /* Call sites don't need the result length so it's not accumulated. */
81514 while (count-- > 0) {
81515 duk__append_u32(re_ctx, (duk_uint32_t) (*values++));
81516 }
81517}
81518
81519DUK_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) {
81520 DUK_BW_INSERT_ENSURE_SLICE(re_ctx->thr, &re_ctx->bw, offset, data_offset, data_length);
81521}
81522
81523DUK_LOCAL void duk__append_slice(duk_re_compiler_ctx *re_ctx, duk_uint32_t data_offset, duk_uint32_t data_length) {
81524 DUK_BW_WRITE_ENSURE_SLICE(re_ctx->thr, &re_ctx->bw, data_offset, data_length);
81525}
81526
81527DUK_LOCAL void duk__remove_slice(duk_re_compiler_ctx *re_ctx, duk_uint32_t data_offset, duk_uint32_t data_length) {
81528 DUK_BW_REMOVE_ENSURE_SLICE(re_ctx->thr, &re_ctx->bw, data_offset, data_length);
81529}
81530
81531/*
81532 * Insert a jump offset at 'offset' to complete an instruction
81533 * (the jump offset is always the last component of an instruction).
81534 * The 'skip' argument must be computed relative to 'offset',
81535 * -without- taking into account the skip field being inserted.
81536 *
81537 * ... A B C ins X Y Z ... (ins may be a JUMP, SPLIT1/SPLIT2, etc)
81538 * => ... A B C ins SKIP X Y Z
81539 *
81540 * Computing the final (adjusted) skip value, which is relative to the
81541 * first byte of the next instruction, is a bit tricky because of the
81542 * variable length UTF-8 encoding. See doc/regexp.rst for discussion.
81543 */
81544DUK_LOCAL duk_uint32_t duk__insert_jump_offset(duk_re_compiler_ctx *re_ctx, duk_uint32_t offset, duk_int32_t skip) {
81545#if 0
81546 /* Iterative solution. */
81547 if (skip < 0) {
81548 duk_small_int_t len;
81549 /* two encoding attempts suffices */
81550 len = duk_unicode_get_xutf8_length((duk_codepoint_t) duk__encode_i32(skip));
81551 len = duk_unicode_get_xutf8_length((duk_codepoint_t) duk__encode_i32(skip - (duk_int32_t) len));
81552 DUK_ASSERT(duk_unicode_get_xutf8_length(duk__encode_i32(skip - (duk_int32_t) len)) == len); /* no change */
81553 skip -= (duk_int32_t) len;
81554 }
81555#endif
81556
81557#if defined(DUK_USE_PREFER_SIZE)
81558 /* Closed form solution, this produces smallest code.
81559 * See re_neg_jump_offset (closed2).
81560 */
81561 if (skip < 0) {
81562 skip--;
81563 if (skip < -0x3fL) {
81564 skip--;
81565 }
81566 if (skip < -0x3ffL) {
81567 skip--;
81568 }
81569 if (skip < -0x7fffL) {
81570 skip--;
81571 }
81572 if (skip < -0xfffffL) {
81573 skip--;
81574 }
81575 if (skip < -0x1ffffffL) {
81576 skip--;
81577 }
81578 if (skip < -0x3fffffffL) {
81579 skip--;
81580 }
81581 }
81582#else /* DUK_USE_PREFER_SIZE */
81583 /* Closed form solution, this produces fastest code.
81584 * See re_neg_jump_offset (closed1).
81585 */
81586 if (skip < 0) {
81587 if (skip >= -0x3eL) {
81588 skip -= 1;
81589 } else if (skip >= -0x3fdL) {
81590 skip -= 2;
81591 } else if (skip >= -0x7ffcL) {
81592 skip -= 3;
81593 } else if (skip >= -0xffffbL) {
81594 skip -= 4;
81595 } else if (skip >= -0x1fffffaL) {
81596 skip -= 5;
81597 } else if (skip >= -0x3ffffff9L) {
81598 skip -= 6;
81599 } else {
81600 skip -= 7;
81601 }
81602 }
81603#endif /* DUK_USE_PREFER_SIZE */
81604
81605 return duk__insert_i32(re_ctx, offset, skip);
81606}
81607
81608DUK_LOCAL duk_uint32_t duk__append_jump_offset(duk_re_compiler_ctx *re_ctx, duk_int32_t skip) {
81609 return (duk_uint32_t) duk__insert_jump_offset(re_ctx, (duk_uint32_t) DUK__RE_BUFLEN(re_ctx), skip);
81610}
81611
81612/*
81613 * duk_re_range_callback for generating character class ranges.
81614 *
81615 * When ignoreCase is false, the range is simply emitted as is.
81616 * We don't, for instance, eliminate duplicates or overlapping
81617 * ranges in a character class.
81618 *
81619 * When ignoreCase is true, the range needs to be normalized through
81620 * canonicalization. Unfortunately a canonicalized version of a
81621 * continuous range is not necessarily continuous (e.g. [x-{] is
81622 * continuous but [X-{] is not). The current algorithm creates the
81623 * canonicalized range(s) space efficiently at the cost of compile
81624 * time execution time (see doc/regexp.rst for discussion).
81625 *
81626 * Note that the ctx->nranges is a context-wide temporary value
81627 * (this is OK because there cannot be multiple character classes
81628 * being parsed simultaneously).
81629 */
81630
81631DUK_LOCAL void duk__generate_ranges(void *userdata, duk_codepoint_t r1, duk_codepoint_t r2, duk_bool_t direct) {
81632 duk_re_compiler_ctx *re_ctx = (duk_re_compiler_ctx *) userdata;
81633
81634 DUK_DD(DUK_DDPRINT("duk__generate_ranges(): re_ctx=%p, range=[%ld,%ld] direct=%ld",
81635 (void *) re_ctx, (long) r1, (long) r2, (long) direct));
81636
81637 if (!direct && (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE)) {
81638 /*
81639 * Canonicalize a range, generating result ranges as necessary.
81640 * Needs to exhaustively scan the entire range (at most 65536
81641 * code points). If 'direct' is set, caller (lexer) has ensured
81642 * that the range is already canonicalization compatible (this
81643 * is used to avoid unnecessary canonicalization of built-in
81644 * ranges like \W, which are not affected by canonicalization).
81645 *
81646 * NOTE: here is one place where we don't want to support chars
81647 * outside the BMP, because the exhaustive search would be
81648 * massively larger.
81649 */
81650
81651 duk_codepoint_t i;
81652 duk_codepoint_t t;
81653 duk_codepoint_t r_start, r_end;
81654
81655 r_start = duk_unicode_re_canonicalize_char(re_ctx->thr, r1);
81656 r_end = r_start;
81657 for (i = r1 + 1; i <= r2; i++) {
81658 t = duk_unicode_re_canonicalize_char(re_ctx->thr, i);
81659 if (t == r_end + 1) {
81660 r_end = t;
81661 } else {
81662 DUK_DD(DUK_DDPRINT("canonicalized, emit range: [%ld,%ld]", (long) r_start, (long) r_end));
81663 duk__append_u32(re_ctx, (duk_uint32_t) r_start);
81664 duk__append_u32(re_ctx, (duk_uint32_t) r_end);
81665 re_ctx->nranges++;
81666 r_start = t;
81667 r_end = t;
81668 }
81669 }
81670 DUK_DD(DUK_DDPRINT("canonicalized, emit range: [%ld,%ld]", (long) r_start, (long) r_end));
81671 duk__append_u32(re_ctx, (duk_uint32_t) r_start);
81672 duk__append_u32(re_ctx, (duk_uint32_t) r_end);
81673 re_ctx->nranges++;
81674 } else {
81675 DUK_DD(DUK_DDPRINT("direct, emit range: [%ld,%ld]", (long) r1, (long) r2));
81676 duk__append_u32(re_ctx, (duk_uint32_t) r1);
81677 duk__append_u32(re_ctx, (duk_uint32_t) r2);
81678 re_ctx->nranges++;
81679 }
81680}
81681
81682/*
81683 * Parse regexp Disjunction. Most of regexp compilation happens here.
81684 *
81685 * Handles Disjunction, Alternative, and Term productions directly without
81686 * recursion. The only constructs requiring recursion are positive/negative
81687 * lookaheads, capturing parentheses, and non-capturing parentheses.
81688 *
81689 * The function determines whether the entire disjunction is a 'simple atom'
81690 * (see doc/regexp.rst discussion on 'simple quantifiers') and if so,
81691 * returns the atom character length which is needed by the caller to keep
81692 * track of its own atom character length. A disjunction with more than one
81693 * alternative is never considered a simple atom (although in some cases
81694 * that might be the case).
81695 *
81696 * Return value: simple atom character length or < 0 if not a simple atom.
81697 * Appends the bytecode for the disjunction matcher to the end of the temp
81698 * buffer.
81699 *
81700 * Regexp top level structure is:
81701 *
81702 * Disjunction = Term*
81703 * | Term* | Disjunction
81704 *
81705 * Term = Assertion
81706 * | Atom
81707 * | Atom Quantifier
81708 *
81709 * An empty Term sequence is a valid disjunction alternative (e.g. /|||c||/).
81710 *
81711 * Notes:
81712 *
81713 * * Tracking of the 'simple-ness' of the current atom vs. the entire
81714 * disjunction are separate matters. For instance, the disjunction
81715 * may be complex, but individual atoms may be simple. Furthermore,
81716 * simple quantifiers are used whenever possible, even if the
81717 * disjunction as a whole is complex.
81718 *
81719 * * The estimate of whether an atom is simple is conservative now,
81720 * and it would be possible to expand it. For instance, captures
81721 * cause the disjunction to be marked complex, even though captures
81722 * -can- be handled by simple quantifiers with some minor modifications.
81723 *
81724 * * Disjunction 'tainting' as 'complex' is handled at the end of the
81725 * main for loop collectively for atoms. Assertions, quantifiers,
81726 * and '|' tokens need to taint the result manually if necessary.
81727 * Assertions cannot add to result char length, only atoms (and
81728 * quantifiers) can; currently quantifiers will taint the result
81729 * as complex though.
81730 */
81731
81732DUK_LOCAL const duk_uint16_t * const duk__re_range_lookup1[3] = {
81733 duk_unicode_re_ranges_digit,
81734 duk_unicode_re_ranges_white,
81735 duk_unicode_re_ranges_wordchar
81736};
81737DUK_LOCAL const duk_uint8_t duk__re_range_lookup2[3] = {
81738 sizeof(duk_unicode_re_ranges_digit) / (2 * sizeof(duk_uint16_t)),
81739 sizeof(duk_unicode_re_ranges_white) / (2 * sizeof(duk_uint16_t)),
81740 sizeof(duk_unicode_re_ranges_wordchar) / (2 * sizeof(duk_uint16_t))
81741};
81742
81743DUK_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) {
81744#if 0
81745 DUK_ASSERT(re_op <= 0x7fUL);
81746 DUK_ASSERT(count <= 0x7fUL);
81747 duk__append_2bytes(re_ctx, (duk_uint8_t) re_op, (duk_uint8_t) count);
81748#endif
81749 duk__append_reop(re_ctx, re_op);
81750 duk__append_7bit(re_ctx, count);
81751 duk__append_u16_list(re_ctx, ranges, count * 2);
81752}
81753
81754DUK_LOCAL void duk__parse_disjunction(duk_re_compiler_ctx *re_ctx, duk_bool_t expect_eof, duk__re_disjunction_info *out_atom_info) {
81755 duk_int32_t atom_start_offset = -1; /* negative -> no atom matched on previous round */
81756 duk_int32_t atom_char_length = 0; /* negative -> complex atom */
81757 duk_uint32_t atom_start_captures = re_ctx->captures; /* value of re_ctx->captures at start of atom */
81758 duk_int32_t unpatched_disjunction_split = -1;
81759 duk_int32_t unpatched_disjunction_jump = -1;
81760 duk_uint32_t entry_offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx);
81761 duk_int32_t res_charlen = 0; /* -1 if disjunction is complex, char length if simple */
81762 duk__re_disjunction_info tmp_disj;
81763
81764 DUK_ASSERT(out_atom_info != NULL);
81765
81766 if (re_ctx->recursion_depth >= re_ctx->recursion_limit) {
81767 DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_REGEXP_COMPILER_RECURSION_LIMIT);
81768 }
81769 re_ctx->recursion_depth++;
81770
81771#if 0
81772 out_atom_info->start_captures = re_ctx->captures;
81773#endif
81774
81775 for (;;) {
81776 /* atom_char_length, atom_start_offset, atom_start_offset reflect the
81777 * atom matched on the previous loop. If a quantifier is encountered
81778 * on this loop, these are needed to handle the quantifier correctly.
81779 * new_atom_char_length etc are for the atom parsed on this round;
81780 * they're written to atom_char_length etc at the end of the round.
81781 */
81782 duk_int32_t new_atom_char_length; /* char length of the atom parsed in this loop */
81783 duk_int32_t new_atom_start_offset; /* bytecode start offset of the atom parsed in this loop
81784 * (allows quantifiers to copy the atom bytecode)
81785 */
81786 duk_uint32_t new_atom_start_captures; /* re_ctx->captures at the start of the atom parsed in this loop */
81787
81788 duk_lexer_parse_re_token(&re_ctx->lex, &re_ctx->curr_token);
81789
81790 DUK_DD(DUK_DDPRINT("re token: %ld (num=%ld, char=%c)",
81791 (long) re_ctx->curr_token.t,
81792 (long) re_ctx->curr_token.num,
81793 (re_ctx->curr_token.num >= 0x20 && re_ctx->curr_token.num <= 0x7e) ?
81794 (int) re_ctx->curr_token.num : (int) '?'));
81795
81796 /* set by atom case clauses */
81797 new_atom_start_offset = -1;
81798 new_atom_char_length = -1;
81799 new_atom_start_captures = re_ctx->captures;
81800
81801 switch (re_ctx->curr_token.t) {
81802 case DUK_RETOK_DISJUNCTION: {
81803 /*
81804 * The handling here is a bit tricky. If a previous '|' has been processed,
81805 * we have a pending split1 and a pending jump (for a previous match). These
81806 * need to be back-patched carefully. See docs for a detailed example.
81807 */
81808
81809 /* patch pending jump and split */
81810 if (unpatched_disjunction_jump >= 0) {
81811 duk_uint32_t offset;
81812
81813 DUK_ASSERT(unpatched_disjunction_split >= 0);
81814 offset = unpatched_disjunction_jump;
81815 offset += duk__insert_jump_offset(re_ctx,
81816 offset,
81817 (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - offset));
81818 /* offset is now target of the pending split (right after jump) */
81819 duk__insert_jump_offset(re_ctx,
81820 unpatched_disjunction_split,
81821 offset - unpatched_disjunction_split);
81822 }
81823
81824 /* add a new pending split to the beginning of the entire disjunction */
81825 (void) duk__insert_u32(re_ctx,
81826 entry_offset,
81827 DUK_REOP_SPLIT1); /* prefer direct execution */
81828 unpatched_disjunction_split = entry_offset + 1; /* +1 for opcode */
81829
81830 /* add a new pending match jump for latest finished alternative */
81831 duk__append_reop(re_ctx, DUK_REOP_JUMP);
81832 unpatched_disjunction_jump = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
81833
81834 /* 'taint' result as complex */
81835 res_charlen = -1;
81836 break;
81837 }
81838 case DUK_RETOK_QUANTIFIER: {
81839 if (atom_start_offset < 0) {
81840 DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_INVALID_QUANTIFIER_NO_ATOM);
81841 }
81842 if (re_ctx->curr_token.qmin > re_ctx->curr_token.qmax) {
81843 DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_INVALID_QUANTIFIER_VALUES);
81844 }
81845 if (atom_char_length >= 0) {
81846 /*
81847 * Simple atom
81848 *
81849 * If atom_char_length is zero, we'll have unbounded execution time for e.g.
81850 * /()*x/.exec('x'). We can't just skip the match because it might have some
81851 * side effects (for instance, if we allowed captures in simple atoms, the
81852 * capture needs to happen). The simple solution below is to force the
81853 * quantifier to match at most once, since the additional matches have no effect.
81854 *
81855 * With a simple atom there can be no capture groups, so no captures need
81856 * to be reset.
81857 */
81858 duk_int32_t atom_code_length;
81859 duk_uint32_t offset;
81860 duk_uint32_t qmin, qmax;
81861
81862 qmin = re_ctx->curr_token.qmin;
81863 qmax = re_ctx->curr_token.qmax;
81864 if (atom_char_length == 0) {
81865 /* qmin and qmax will be 0 or 1 */
81866 if (qmin > 1) {
81867 qmin = 1;
81868 }
81869 if (qmax > 1) {
81870 qmax = 1;
81871 }
81872 }
81873
81874 duk__append_reop(re_ctx, DUK_REOP_MATCH); /* complete 'sub atom' */
81875 atom_code_length = (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - atom_start_offset);
81876
81877 offset = atom_start_offset;
81878 if (re_ctx->curr_token.greedy) {
81879 offset += duk__insert_u32(re_ctx, offset, DUK_REOP_SQGREEDY);
81880 offset += duk__insert_u32(re_ctx, offset, qmin);
81881 offset += duk__insert_u32(re_ctx, offset, qmax);
81882 offset += duk__insert_u32(re_ctx, offset, atom_char_length);
81883 offset += duk__insert_jump_offset(re_ctx, offset, atom_code_length);
81884 } else {
81885 offset += duk__insert_u32(re_ctx, offset, DUK_REOP_SQMINIMAL);
81886 offset += duk__insert_u32(re_ctx, offset, qmin);
81887 offset += duk__insert_u32(re_ctx, offset, qmax);
81888 offset += duk__insert_jump_offset(re_ctx, offset, atom_code_length);
81889 }
81890 DUK_UNREF(offset); /* silence scan-build warning */
81891 } else {
81892 /*
81893 * Complex atom
81894 *
81895 * The original code is used as a template, and removed at the end
81896 * (this differs from the handling of simple quantifiers).
81897 *
81898 * NOTE: there is no current solution for empty atoms in complex
81899 * quantifiers. This would need some sort of a 'progress' instruction.
81900 *
81901 * XXX: impose limit on maximum result size, i.e. atom_code_len * atom_copies?
81902 */
81903 duk_int32_t atom_code_length;
81904 duk_uint32_t atom_copies;
81905 duk_uint32_t tmp_qmin, tmp_qmax;
81906
81907 /* pre-check how many atom copies we're willing to make (atom_copies not needed below) */
81908 atom_copies = (re_ctx->curr_token.qmax == DUK_RE_QUANTIFIER_INFINITE) ?
81909 re_ctx->curr_token.qmin : re_ctx->curr_token.qmax;
81910 if (atom_copies > DUK_RE_MAX_ATOM_COPIES) {
81911 DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_QUANTIFIER_TOO_MANY_COPIES);
81912 }
81913
81914 /* wipe the capture range made by the atom (if any) */
81915 DUK_ASSERT(atom_start_captures <= re_ctx->captures);
81916 if (atom_start_captures != re_ctx->captures) {
81917 DUK_ASSERT(atom_start_captures < re_ctx->captures);
81918 DUK_DDD(DUK_DDDPRINT("must wipe ]atom_start_captures,re_ctx->captures]: ]%ld,%ld]",
81919 (long) atom_start_captures, (long) re_ctx->captures));
81920
81921 /* insert (DUK_REOP_WIPERANGE, start, count) in reverse order so the order ends up right */
81922 duk__insert_u32(re_ctx, atom_start_offset, (re_ctx->captures - atom_start_captures) * 2);
81923 duk__insert_u32(re_ctx, atom_start_offset, (atom_start_captures + 1) * 2);
81924 duk__insert_u32(re_ctx, atom_start_offset, DUK_REOP_WIPERANGE);
81925 } else {
81926 DUK_DDD(DUK_DDDPRINT("no need to wipe captures: atom_start_captures == re_ctx->captures == %ld",
81927 (long) atom_start_captures));
81928 }
81929
81930 atom_code_length = (duk_int32_t) DUK__RE_BUFLEN(re_ctx) - atom_start_offset;
81931
81932 /* insert the required matches (qmin) by copying the atom */
81933 tmp_qmin = re_ctx->curr_token.qmin;
81934 tmp_qmax = re_ctx->curr_token.qmax;
81935 while (tmp_qmin > 0) {
81936 duk__append_slice(re_ctx, atom_start_offset, atom_code_length);
81937 tmp_qmin--;
81938 if (tmp_qmax != DUK_RE_QUANTIFIER_INFINITE) {
81939 tmp_qmax--;
81940 }
81941 }
81942 DUK_ASSERT(tmp_qmin == 0);
81943
81944 /* insert code for matching the remainder - infinite or finite */
81945 if (tmp_qmax == DUK_RE_QUANTIFIER_INFINITE) {
81946 /* reuse last emitted atom for remaining 'infinite' quantifier */
81947
81948 if (re_ctx->curr_token.qmin == 0) {
81949 /* Special case: original qmin was zero so there is nothing
81950 * to repeat. Emit an atom copy but jump over it here.
81951 */
81952 duk__append_reop(re_ctx, DUK_REOP_JUMP);
81953 duk__append_jump_offset(re_ctx, atom_code_length);
81954 duk__append_slice(re_ctx, atom_start_offset, atom_code_length);
81955 }
81956 if (re_ctx->curr_token.greedy) {
81957 duk__append_reop(re_ctx, DUK_REOP_SPLIT2); /* prefer jump */
81958 } else {
81959 duk__append_reop(re_ctx, DUK_REOP_SPLIT1); /* prefer direct */
81960 }
81961 duk__append_jump_offset(re_ctx, -atom_code_length - 1); /* -1 for opcode */
81962 } else {
81963 /*
81964 * The remaining matches are emitted as sequence of SPLITs and atom
81965 * copies; the SPLITs skip the remaining copies and match the sequel.
81966 * This sequence needs to be emitted starting from the last copy
81967 * because the SPLITs are variable length due to the variable length
81968 * skip offset. This causes a lot of memory copying now.
81969 *
81970 * Example structure (greedy, match maximum # atoms):
81971 *
81972 * SPLIT1 LSEQ
81973 * (atom)
81974 * SPLIT1 LSEQ ; <- the byte length of this instruction is needed
81975 * (atom) ; to encode the above SPLIT1 correctly
81976 * ...
81977 * LSEQ:
81978 */
81979 duk_uint32_t offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx);
81980 while (tmp_qmax > 0) {
81981 duk__insert_slice(re_ctx, offset, atom_start_offset, atom_code_length);
81982 if (re_ctx->curr_token.greedy) {
81983 duk__insert_u32(re_ctx, offset, DUK_REOP_SPLIT1); /* prefer direct */
81984 } else {
81985 duk__insert_u32(re_ctx, offset, DUK_REOP_SPLIT2); /* prefer jump */
81986 }
81987 duk__insert_jump_offset(re_ctx,
81988 offset + 1, /* +1 for opcode */
81989 (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - (offset + 1)));
81990 tmp_qmax--;
81991 }
81992 }
81993
81994 /* remove the original 'template' atom */
81995 duk__remove_slice(re_ctx, atom_start_offset, atom_code_length);
81996 }
81997
81998 /* 'taint' result as complex */
81999 res_charlen = -1;
82000 break;
82001 }
82002 case DUK_RETOK_ASSERT_START: {
82003 duk__append_reop(re_ctx, DUK_REOP_ASSERT_START);
82004 break;
82005 }
82006 case DUK_RETOK_ASSERT_END: {
82007 duk__append_reop(re_ctx, DUK_REOP_ASSERT_END);
82008 break;
82009 }
82010 case DUK_RETOK_ASSERT_WORD_BOUNDARY: {
82011 duk__append_reop(re_ctx, DUK_REOP_ASSERT_WORD_BOUNDARY);
82012 break;
82013 }
82014 case DUK_RETOK_ASSERT_NOT_WORD_BOUNDARY: {
82015 duk__append_reop(re_ctx, DUK_REOP_ASSERT_NOT_WORD_BOUNDARY);
82016 break;
82017 }
82018 case DUK_RETOK_ASSERT_START_POS_LOOKAHEAD:
82019 case DUK_RETOK_ASSERT_START_NEG_LOOKAHEAD: {
82020 duk_uint32_t offset;
82021 duk_uint32_t opcode = (re_ctx->curr_token.t == DUK_RETOK_ASSERT_START_POS_LOOKAHEAD) ?
82022 DUK_REOP_LOOKPOS : DUK_REOP_LOOKNEG;
82023
82024 offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx);
82025 duk__parse_disjunction(re_ctx, 0, &tmp_disj);
82026 duk__append_reop(re_ctx, DUK_REOP_MATCH);
82027
82028 (void) duk__insert_u32(re_ctx, offset, opcode);
82029 (void) duk__insert_jump_offset(re_ctx,
82030 offset + 1, /* +1 for opcode */
82031 (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - (offset + 1)));
82032
82033 /* 'taint' result as complex -- this is conservative,
82034 * as lookaheads do not backtrack.
82035 */
82036 res_charlen = -1;
82037 break;
82038 }
82039 case DUK_RETOK_ATOM_PERIOD: {
82040 new_atom_char_length = 1;
82041 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
82042 duk__append_reop(re_ctx, DUK_REOP_PERIOD);
82043 break;
82044 }
82045 case DUK_RETOK_ATOM_CHAR: {
82046 /* Note: successive characters could be joined into string matches
82047 * but this is not trivial (consider e.g. '/xyz+/); see docs for
82048 * more discussion.
82049 *
82050 * No support for \u{H+} yet. While only BMP Unicode escapes are
82051 * supported for RegExps at present, 'ch' may still be a non-BMP
82052 * codepoint if it is decoded straight from source text UTF-8.
82053 * There's no non-BMP support yet so this is handled simply by
82054 * matching the non-BMP character (which is custom behavior).
82055 */
82056 duk_uint32_t ch;
82057
82058 new_atom_char_length = 1;
82059 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
82060 duk__append_reop(re_ctx, DUK_REOP_CHAR);
82061 ch = re_ctx->curr_token.num;
82062 if (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) {
82063 ch = duk_unicode_re_canonicalize_char(re_ctx->thr, ch);
82064 }
82065 duk__append_u32(re_ctx, ch);
82066 break;
82067 }
82068 case DUK_RETOK_ATOM_DIGIT:
82069 case DUK_RETOK_ATOM_NOT_DIGIT:
82070 case DUK_RETOK_ATOM_WHITE:
82071 case DUK_RETOK_ATOM_NOT_WHITE:
82072 case DUK_RETOK_ATOM_WORD_CHAR:
82073 case DUK_RETOK_ATOM_NOT_WORD_CHAR: {
82074 duk_small_uint_t re_op;
82075 duk_small_uint_t idx;
82076
82077 new_atom_char_length = 1;
82078 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
82079
82080 DUK_ASSERT((DUK_RETOK_ATOM_DIGIT & 0x01) != 0);
82081 DUK_ASSERT((DUK_RETOK_ATOM_WHITE & 0x01) != 0);
82082 DUK_ASSERT((DUK_RETOK_ATOM_WORD_CHAR & 0x01) != 0);
82083 DUK_ASSERT((DUK_RETOK_ATOM_NOT_DIGIT & 0x01) == 0);
82084 DUK_ASSERT((DUK_RETOK_ATOM_NOT_WHITE & 0x01) == 0);
82085 DUK_ASSERT((DUK_RETOK_ATOM_NOT_WORD_CHAR & 0x01) == 0);
82086 re_op = (re_ctx->curr_token.t & 0x01) ? DUK_REOP_RANGES : DUK_REOP_INVRANGES;
82087
82088 DUK_ASSERT(DUK_RETOK_ATOM_WHITE == DUK_RETOK_ATOM_DIGIT + 2);
82089 DUK_ASSERT(DUK_RETOK_ATOM_WORD_CHAR == DUK_RETOK_ATOM_DIGIT + 4);
82090 idx = (re_ctx->curr_token.t - DUK_RETOK_ATOM_DIGIT) >> 1;
82091 DUK_ASSERT(idx <= 2); /* Assume continuous token numbers; also checks negative underflow. */
82092
82093 duk__append_range_atom_matcher(re_ctx, re_op, duk__re_range_lookup1[idx], duk__re_range_lookup2[idx]);
82094 break;
82095 }
82096 case DUK_RETOK_ATOM_BACKREFERENCE: {
82097 duk_uint32_t backref = (duk_uint32_t) re_ctx->curr_token.num;
82098 if (backref > re_ctx->highest_backref) {
82099 re_ctx->highest_backref = backref;
82100 }
82101 new_atom_char_length = -1; /* mark as complex */
82102 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
82103 duk__append_reop(re_ctx, DUK_REOP_BACKREFERENCE);
82104 duk__append_u32(re_ctx, backref);
82105 break;
82106 }
82107 case DUK_RETOK_ATOM_START_CAPTURE_GROUP: {
82108 duk_uint32_t cap;
82109
82110 new_atom_char_length = -1; /* mark as complex (capture handling) */
82111 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
82112 cap = ++re_ctx->captures;
82113 duk__append_reop(re_ctx, DUK_REOP_SAVE);
82114 duk__append_u32(re_ctx, cap * 2);
82115 duk__parse_disjunction(re_ctx, 0, &tmp_disj); /* retval (sub-atom char length) unused, tainted as complex above */
82116 duk__append_reop(re_ctx, DUK_REOP_SAVE);
82117 duk__append_u32(re_ctx, cap * 2 + 1);
82118 break;
82119 }
82120 case DUK_RETOK_ATOM_START_NONCAPTURE_GROUP: {
82121 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
82122 duk__parse_disjunction(re_ctx, 0, &tmp_disj);
82123 new_atom_char_length = tmp_disj.charlen;
82124 break;
82125 }
82126 case DUK_RETOK_ATOM_START_CHARCLASS:
82127 case DUK_RETOK_ATOM_START_CHARCLASS_INVERTED: {
82128 /*
82129 * Range parsing is done with a special lexer function which calls
82130 * us for every range parsed. This is different from how rest of
82131 * the parsing works, but avoids a heavy, arbitrary size intermediate
82132 * value type to hold the ranges.
82133 *
82134 * Another complication is the handling of character ranges when
82135 * case insensitive matching is used (see docs for discussion).
82136 * The range handler callback given to the lexer takes care of this
82137 * as well.
82138 *
82139 * Note that duplicate ranges are not eliminated when parsing character
82140 * classes, so that canonicalization of
82141 *
82142 * [0-9a-fA-Fx-{]
82143 *
82144 * creates the result (note the duplicate ranges):
82145 *
82146 * [0-9A-FA-FX-Z{-{]
82147 *
82148 * where [x-{] is split as a result of canonicalization. The duplicate
82149 * ranges are not a semantics issue: they work correctly.
82150 */
82151
82152 duk_uint32_t offset;
82153
82154 DUK_DD(DUK_DDPRINT("character class"));
82155
82156 /* insert ranges instruction, range count patched in later */
82157 new_atom_char_length = 1;
82158 new_atom_start_offset = (duk_int32_t) DUK__RE_BUFLEN(re_ctx);
82159 duk__append_reop(re_ctx,
82160 (re_ctx->curr_token.t == DUK_RETOK_ATOM_START_CHARCLASS) ?
82161 DUK_REOP_RANGES : DUK_REOP_INVRANGES);
82162 offset = (duk_uint32_t) DUK__RE_BUFLEN(re_ctx); /* patch in range count later */
82163
82164 /* parse ranges until character class ends */
82165 re_ctx->nranges = 0; /* note: ctx-wide temporary */
82166 duk_lexer_parse_re_ranges(&re_ctx->lex, duk__generate_ranges, (void *) re_ctx);
82167
82168 /* insert range count */
82169 duk__insert_u32(re_ctx, offset, re_ctx->nranges);
82170 break;
82171 }
82172 case DUK_RETOK_ATOM_END_GROUP: {
82173 if (expect_eof) {
82174 DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_UNEXPECTED_CLOSING_PAREN);
82175 }
82176 goto done;
82177 }
82178 case DUK_RETOK_EOF: {
82179 if (!expect_eof) {
82180 DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_UNEXPECTED_END_OF_PATTERN);
82181 }
82182 goto done;
82183 }
82184 default: {
82185 DUK_ERROR_SYNTAX(re_ctx->thr, DUK_STR_UNEXPECTED_REGEXP_TOKEN);
82186 }
82187 }
82188
82189 /* a complex (new) atom taints the result */
82190 if (new_atom_start_offset >= 0) {
82191 if (new_atom_char_length < 0) {
82192 res_charlen = -1;
82193 } else if (res_charlen >= 0) {
82194 /* only advance if not tainted */
82195 res_charlen += new_atom_char_length;
82196 }
82197 }
82198
82199 /* record previous atom info in case next token is a quantifier */
82200 atom_start_offset = new_atom_start_offset;
82201 atom_char_length = new_atom_char_length;
82202 atom_start_captures = new_atom_start_captures;
82203 }
82204
82205 done:
82206
82207 /* finish up pending jump and split for last alternative */
82208 if (unpatched_disjunction_jump >= 0) {
82209 duk_uint32_t offset;
82210
82211 DUK_ASSERT(unpatched_disjunction_split >= 0);
82212 offset = unpatched_disjunction_jump;
82213 offset += duk__insert_jump_offset(re_ctx,
82214 offset,
82215 (duk_int32_t) (DUK__RE_BUFLEN(re_ctx) - offset));
82216 /* offset is now target of the pending split (right after jump) */
82217 duk__insert_jump_offset(re_ctx,
82218 unpatched_disjunction_split,
82219 offset - unpatched_disjunction_split);
82220 }
82221
82222#if 0
82223 out_atom_info->end_captures = re_ctx->captures;
82224#endif
82225 out_atom_info->charlen = res_charlen;
82226 DUK_DDD(DUK_DDDPRINT("parse disjunction finished: charlen=%ld",
82227 (long) out_atom_info->charlen));
82228
82229 re_ctx->recursion_depth--;
82230}
82231
82232/*
82233 * Flags parsing (see E5 Section 15.10.4.1).
82234 */
82235
82236DUK_LOCAL duk_uint32_t duk__parse_regexp_flags(duk_hthread *thr, duk_hstring *h) {
82237 const duk_uint8_t *p;
82238 const duk_uint8_t *p_end;
82239 duk_uint32_t flags = 0;
82240
82241 p = DUK_HSTRING_GET_DATA(h);
82242 p_end = p + DUK_HSTRING_GET_BYTELEN(h);
82243
82244 /* Note: can be safely scanned as bytes (undecoded) */
82245
82246 while (p < p_end) {
82247 duk_uint8_t c = *p++;
82248 switch (c) {
82249 case (duk_uint8_t) 'g': {
82250 if (flags & DUK_RE_FLAG_GLOBAL) {
82251 goto error;
82252 }
82253 flags |= DUK_RE_FLAG_GLOBAL;
82254 break;
82255 }
82256 case (duk_uint8_t) 'i': {
82257 if (flags & DUK_RE_FLAG_IGNORE_CASE) {
82258 goto error;
82259 }
82260 flags |= DUK_RE_FLAG_IGNORE_CASE;
82261 break;
82262 }
82263 case (duk_uint8_t) 'm': {
82264 if (flags & DUK_RE_FLAG_MULTILINE) {
82265 goto error;
82266 }
82267 flags |= DUK_RE_FLAG_MULTILINE;
82268 break;
82269 }
82270 default: {
82271 goto error;
82272 }
82273 }
82274 }
82275
82276 return flags;
82277
82278 error:
82279 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_REGEXP_FLAGS);
82280 return 0; /* never here */
82281}
82282
82283/*
82284 * Create escaped RegExp source (E5 Section 15.10.3).
82285 *
82286 * The current approach is to special case the empty RegExp
82287 * ('' -> '(?:)') and otherwise replace unescaped '/' characters
82288 * with '\/' regardless of where they occur in the regexp.
82289 *
82290 * Note that normalization does not seem to be necessary for
82291 * RegExp literals (e.g. '/foo/') because to be acceptable as
82292 * a RegExp literal, the text between forward slashes must
82293 * already match the escaping requirements (e.g. must not contain
82294 * unescaped forward slashes or be empty). Escaping IS needed
82295 * for expressions like 'new Regexp("...", "")' however.
82296 * Currently, we re-escape in either case.
82297 *
82298 * Also note that we process the source here in UTF-8 encoded
82299 * form. This is correct, because any non-ASCII characters are
82300 * passed through without change.
82301 */
82302
82303DUK_LOCAL void duk__create_escaped_source(duk_hthread *thr, int idx_pattern) {
82304 duk_context *ctx = (duk_context *) thr;
82305 duk_hstring *h;
82306 const duk_uint8_t *p;
82307 duk_bufwriter_ctx bw_alloc;
82309 duk_uint8_t *q;
82310 duk_size_t i, n;
82311 duk_uint_fast8_t c_prev, c;
82312
82313 h = duk_known_hstring(ctx, idx_pattern);
82314 p = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h);
82315 n = (duk_size_t) DUK_HSTRING_GET_BYTELEN(h);
82316
82317 if (n == 0) {
82318 duk_push_string(ctx, "(?:)");
82319 return;
82320 }
82321
82322 bw = &bw_alloc;
82323 DUK_BW_INIT_PUSHBUF(thr, bw, n);
82324 q = DUK_BW_GET_PTR(thr, bw);
82325
82326 c_prev = (duk_uint_fast8_t) 0;
82327
82328 for (i = 0; i < n; i++) {
82329 c = p[i];
82330
82331 q = DUK_BW_ENSURE_RAW(thr, bw, 2, q);
82332
82333 if (c == (duk_uint_fast8_t) '/' && c_prev != (duk_uint_fast8_t) '\\') {
82334 /* Unescaped '/' ANYWHERE in the regexp (in disjunction,
82335 * inside a character class, ...) => same escape works.
82336 */
82337 *q++ = DUK_ASC_BACKSLASH;
82338 }
82339 *q++ = (duk_uint8_t) c;
82340
82341 c_prev = c;
82342 }
82343
82344 DUK_BW_SETPTR_AND_COMPACT(thr, bw, q);
82345 (void) duk_buffer_to_string(ctx, -1); /* Safe if input is safe. */
82346
82347 /* [ ... escaped_source ] */
82348}
82349
82350/*
82351 * Exposed regexp compilation primitive.
82352 *
82353 * Sets up a regexp compilation context, and calls duk__parse_disjunction() to do the
82354 * actual parsing. Handles generation of the compiled regexp header and the
82355 * "boilerplate" capture of the matching substring (save 0 and 1). Also does some
82356 * global level regexp checks after recursive compilation has finished.
82357 *
82358 * An escaped version of the regexp source, suitable for use as a RegExp instance
82359 * 'source' property (see E5 Section 15.10.3), is also left on the stack.
82360 *
82361 * Input stack: [ pattern flags ]
82362 * Output stack: [ bytecode escaped_source ] (both as strings)
82363 */
82364
82365DUK_INTERNAL void duk_regexp_compile(duk_hthread *thr) {
82366 duk_context *ctx = (duk_context *) thr;
82367 duk_re_compiler_ctx re_ctx;
82368 duk_lexer_point lex_point;
82369 duk_hstring *h_pattern;
82370 duk_hstring *h_flags;
82371 duk__re_disjunction_info ign_disj;
82372
82373 DUK_ASSERT(thr != NULL);
82374 DUK_ASSERT(ctx != NULL);
82375
82376 /*
82377 * Args validation
82378 */
82379
82380 /* TypeError if fails */
82381 h_pattern = duk_require_hstring_notsymbol(ctx, -2);
82382 h_flags = duk_require_hstring_notsymbol(ctx, -1);
82383
82384 /*
82385 * Create normalized 'source' property (E5 Section 15.10.3).
82386 */
82387
82388 /* [ ... pattern flags ] */
82389
82390 duk__create_escaped_source(thr, -2);
82391
82392 /* [ ... pattern flags escaped_source ] */
82393
82394 /*
82395 * Init compilation context
82396 */
82397
82398 /* [ ... pattern flags escaped_source buffer ] */
82399
82400 DUK_MEMZERO(&re_ctx, sizeof(re_ctx));
82401 DUK_LEXER_INITCTX(&re_ctx.lex); /* duplicate zeroing, expect for (possible) NULL inits */
82402 re_ctx.thr = thr;
82403 re_ctx.lex.thr = thr;
82404 re_ctx.lex.input = DUK_HSTRING_GET_DATA(h_pattern);
82405 re_ctx.lex.input_length = DUK_HSTRING_GET_BYTELEN(h_pattern);
82406 re_ctx.lex.token_limit = DUK_RE_COMPILE_TOKEN_LIMIT;
82407 re_ctx.recursion_limit = DUK_USE_REGEXP_COMPILER_RECLIMIT;
82408 re_ctx.re_flags = duk__parse_regexp_flags(thr, h_flags);
82409
82410 DUK_BW_INIT_PUSHBUF(thr, &re_ctx.bw, DUK__RE_INITIAL_BUFSIZE);
82411
82412 DUK_DD(DUK_DDPRINT("regexp compiler ctx initialized, flags=0x%08lx, recursion_limit=%ld",
82413 (unsigned long) re_ctx.re_flags, (long) re_ctx.recursion_limit));
82414
82415 /*
82416 * Init lexer
82417 */
82418
82419 lex_point.offset = 0; /* expensive init, just want to fill window */
82420 lex_point.line = 1;
82421 DUK_LEXER_SETPOINT(&re_ctx.lex, &lex_point);
82422
82423 /*
82424 * Compilation
82425 */
82426
82427 DUK_DD(DUK_DDPRINT("starting regexp compilation"));
82428
82429 duk__append_reop(&re_ctx, DUK_REOP_SAVE);
82430 duk__append_7bit(&re_ctx, 0);
82431 duk__parse_disjunction(&re_ctx, 1 /*expect_eof*/, &ign_disj);
82432 duk__append_reop(&re_ctx, DUK_REOP_SAVE);
82433 duk__append_7bit(&re_ctx, 1);
82434 duk__append_reop(&re_ctx, DUK_REOP_MATCH);
82435
82436 /*
82437 * Check for invalid backreferences; note that it is NOT an error
82438 * to back-reference a capture group which has not yet been introduced
82439 * in the pattern (as in /\1(foo)/); in fact, the backreference will
82440 * always match! It IS an error to back-reference a capture group
82441 * which will never be introduced in the pattern. Thus, we can check
82442 * for such references only after parsing is complete.
82443 */
82444
82445 if (re_ctx.highest_backref > re_ctx.captures) {
82446 DUK_ERROR_SYNTAX(thr, DUK_STR_INVALID_BACKREFS);
82447 }
82448
82449 /*
82450 * Emit compiled regexp header: flags, ncaptures
82451 * (insertion order inverted on purpose)
82452 */
82453
82454 duk__insert_u32(&re_ctx, 0, (re_ctx.captures + 1) * 2);
82455 duk__insert_u32(&re_ctx, 0, re_ctx.re_flags);
82456
82457 /* [ ... pattern flags escaped_source buffer ] */
82458
82459 DUK_BW_COMPACT(thr, &re_ctx.bw);
82460 (void) duk_buffer_to_string(ctx, -1); /* Safe because flags is at most 7 bit. */
82461
82462 /* [ ... pattern flags escaped_source bytecode ] */
82463
82464 /*
82465 * Finalize stack
82466 */
82467
82468 duk_remove(ctx, -4); /* -> [ ... flags escaped_source bytecode ] */
82469 duk_remove(ctx, -3); /* -> [ ... escaped_source bytecode ] */
82470
82471 DUK_DD(DUK_DDPRINT("regexp compilation successful, bytecode: %!T, escaped source: %!T",
82472 (duk_tval *) duk_get_tval(ctx, -1), (duk_tval *) duk_get_tval(ctx, -2)));
82473}
82474
82475/*
82476 * Create a RegExp instance (E5 Section 15.10.7).
82477 *
82478 * Note: the output stack left by duk_regexp_compile() is directly compatible
82479 * with the input here.
82480 *
82481 * Input stack: [ escaped_source bytecode ] (both as strings)
82482 * Output stack: [ RegExp ]
82483 */
82484
82485DUK_INTERNAL void duk_regexp_create_instance(duk_hthread *thr) {
82486 duk_context *ctx = (duk_context *) thr;
82487 duk_hobject *h;
82488
82489 /* [ ... escaped_source bytecode ] */
82490
82491 duk_push_object(ctx);
82492 h = duk_known_hobject(ctx, -1);
82493 duk_insert(ctx, -3);
82494
82495 /* [ ... regexp_object escaped_source bytecode ] */
82496
82497 DUK_HOBJECT_SET_CLASS_NUMBER(h, DUK_HOBJECT_CLASS_REGEXP);
82498 DUK_HOBJECT_SET_PROTOTYPE_UPDREF(thr, h, thr->builtins[DUK_BIDX_REGEXP_PROTOTYPE]);
82499
82500 duk_xdef_prop_stridx_short(ctx, -3, DUK_STRIDX_INT_BYTECODE, DUK_PROPDESC_FLAGS_NONE);
82501
82502 /* [ ... regexp_object escaped_source ] */
82503
82504 /* In ES2015 .source, and the .global, .multiline, etc flags are
82505 * inherited getters. Store the escaped source as an internal
82506 * property for the getter.
82507 */
82508
82509 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_SOURCE, DUK_PROPDESC_FLAGS_NONE);
82510
82511 /* [ ... regexp_object ] */
82512
82513 duk_push_int(ctx, 0);
82514 duk_xdef_prop_stridx_short(ctx, -2, DUK_STRIDX_LAST_INDEX, DUK_PROPDESC_FLAGS_W);
82515
82516 /* [ ... regexp_object ] */
82517}
82518
82519#else /* DUK_USE_REGEXP_SUPPORT */
82520
82521/* regexp support disabled */
82522
82523#endif /* DUK_USE_REGEXP_SUPPORT */
82524
82525/* automatic undefs */
82526#undef DUK__RE_BUFLEN
82527#undef DUK__RE_INITIAL_BUFSIZE
82528/*
82529 * Regexp executor.
82530 *
82531 * Safety: the Ecmascript executor should prevent user from reading and
82532 * replacing regexp bytecode. Even so, the executor must validate all
82533 * memory accesses etc. When an invalid access is detected (e.g. a 'save'
82534 * opcode to invalid, unallocated index) it should fail with an internal
82535 * error but not cause a segmentation fault.
82536 *
82537 * Notes:
82538 *
82539 * - Backtrack counts are limited to unsigned 32 bits but should
82540 * technically be duk_size_t for strings longer than 4G chars.
82541 * This also requires a regexp bytecode change.
82542 */
82543
82544/* #include duk_internal.h -> already included */
82545
82546#if defined(DUK_USE_REGEXP_SUPPORT)
82547
82548/*
82549 * Helpers for UTF-8 handling
82550 *
82551 * For bytecode readers the duk_uint32_t and duk_int32_t types are correct
82552 * because they're used for more than just codepoints.
82553 */
82554
82555DUK_LOCAL duk_uint32_t duk__bc_get_u32(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **pc) {
82556 return (duk_uint32_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, pc, re_ctx->bytecode, re_ctx->bytecode_end);
82557}
82558
82559DUK_LOCAL duk_int32_t duk__bc_get_i32(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **pc) {
82560 duk_uint32_t t;
82561
82562 /* signed integer encoding needed to work with UTF-8 */
82563 t = (duk_uint32_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, pc, re_ctx->bytecode, re_ctx->bytecode_end);
82564 if (t & 1) {
82565 return -((duk_int32_t) (t >> 1));
82566 } else {
82567 return (duk_int32_t) (t >> 1);
82568 }
82569}
82570
82571DUK_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) {
82572 const duk_uint8_t *p;
82573
82574 /* Note: allow backtracking from p == ptr_end */
82575 p = *ptr;
82576 if (p < ptr_start || p > ptr_end) {
82577 goto fail;
82578 }
82579
82580 while (count > 0) {
82581 for (;;) {
82582 p--;
82583 if (p < ptr_start) {
82584 goto fail;
82585 }
82586 if ((*p & 0xc0) != 0x80) {
82587 /* utf-8 continuation bytes have the form 10xx xxxx */
82588 break;
82589 }
82590 }
82591 count--;
82592 }
82593 *ptr = p;
82594 return p;
82595
82596 fail:
82597 DUK_ERROR_INTERNAL(thr);
82598 return NULL; /* never here */
82599}
82600
82601DUK_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) {
82602 const duk_uint8_t *p;
82603
82604 p = *ptr;
82605 if (p < ptr_start || p >= ptr_end) {
82606 goto fail;
82607 }
82608
82609 while (count > 0) {
82610 for (;;) {
82611 p++;
82612
82613 /* Note: if encoding ends by hitting end of input, we don't check that
82614 * the encoding is valid, we just assume it is.
82615 */
82616 if (p >= ptr_end || ((*p & 0xc0) != 0x80)) {
82617 /* utf-8 continuation bytes have the form 10xx xxxx */
82618 break;
82619 }
82620 }
82621 count--;
82622 }
82623
82624 *ptr = p;
82625 return p;
82626
82627 fail:
82628 DUK_ERROR_INTERNAL(thr);
82629 return NULL; /* never here */
82630}
82631
82632/*
82633 * Helpers for dealing with the input string
82634 */
82635
82636/* Get a (possibly canonicalized) input character from current sp. The input
82637 * itself is never modified, and captures always record non-canonicalized
82638 * characters even in case-insensitive matching. Return <0 if out of input.
82639 */
82640DUK_LOCAL duk_codepoint_t duk__inp_get_cp(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **sp) {
82641 duk_codepoint_t res;
82642
82643 if (*sp >= re_ctx->input_end) {
82644 return -1;
82645 }
82646 res = (duk_codepoint_t) duk_unicode_decode_xutf8_checked(re_ctx->thr, sp, re_ctx->input, re_ctx->input_end);
82647 if (re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) {
82648 res = duk_unicode_re_canonicalize_char(re_ctx->thr, res);
82649 }
82650 return res;
82651}
82652
82653DUK_LOCAL const duk_uint8_t *duk__inp_backtrack(duk_re_matcher_ctx *re_ctx, const duk_uint8_t **sp, duk_uint_fast32_t count) {
82654 return duk__utf8_backtrack(re_ctx->thr, sp, re_ctx->input, re_ctx->input_end, count);
82655}
82656
82657/* Backtrack utf-8 input and return a (possibly canonicalized) input character. */
82658DUK_LOCAL duk_codepoint_t duk__inp_get_prev_cp(duk_re_matcher_ctx *re_ctx, const duk_uint8_t *sp) {
82659 /* note: caller 'sp' is intentionally not updated here */
82660 (void) duk__inp_backtrack(re_ctx, &sp, (duk_uint_fast32_t) 1);
82661 return duk__inp_get_cp(re_ctx, &sp);
82662}
82663
82664/*
82665 * Regexp recursive matching function.
82666 *
82667 * Returns 'sp' on successful match (points to character after last matched one),
82668 * NULL otherwise.
82669 *
82670 * The C recursion depth limit check is only performed in this function, this
82671 * suffices because the function is present in all true recursion required by
82672 * regexp execution.
82673 */
82674
82675DUK_LOCAL const duk_uint8_t *duk__match_regexp(duk_re_matcher_ctx *re_ctx, const duk_uint8_t *pc, const duk_uint8_t *sp) {
82676 if (re_ctx->recursion_depth >= re_ctx->recursion_limit) {
82677 DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_REGEXP_EXECUTOR_RECURSION_LIMIT);
82678 }
82679 re_ctx->recursion_depth++;
82680
82681 for (;;) {
82682 duk_small_int_t op;
82683
82684 if (re_ctx->steps_count >= re_ctx->steps_limit) {
82685 DUK_ERROR_RANGE(re_ctx->thr, DUK_STR_REGEXP_EXECUTOR_STEP_LIMIT);
82686 }
82687 re_ctx->steps_count++;
82688
82689 /* Opcodes are at most 7 bits now so they encode to one byte. If this
82690 * were not the case or 'pc' is invalid here (due to a bug etc) we'll
82691 * still fail safely through the switch default case.
82692 */
82693 DUK_ASSERT(pc[0] <= 0x7fU);
82694#if 0
82695 op = (duk_small_int_t) duk__bc_get_u32(re_ctx, &pc);
82696#endif
82697 op = *pc++;
82698
82699 DUK_DDD(DUK_DDDPRINT("match: rec=%ld, steps=%ld, pc (after op)=%ld, sp=%ld, op=%ld",
82700 (long) re_ctx->recursion_depth,
82701 (long) re_ctx->steps_count,
82702 (long) (pc - re_ctx->bytecode),
82703 (long) (sp - re_ctx->input),
82704 (long) op));
82705
82706 switch (op) {
82707 case DUK_REOP_MATCH: {
82708 goto match;
82709 }
82710 case DUK_REOP_CHAR: {
82711 /*
82712 * Byte-based matching would be possible for case-sensitive
82713 * matching but not for case-insensitive matching. So, we
82714 * match by decoding the input and bytecode character normally.
82715 *
82716 * Bytecode characters are assumed to be already canonicalized.
82717 * Input characters are canonicalized automatically by
82718 * duk__inp_get_cp() if necessary.
82719 *
82720 * There is no opcode for matching multiple characters. The
82721 * regexp compiler has trouble joining strings efficiently
82722 * during compilation. See doc/regexp.rst for more discussion.
82723 */
82724 duk_codepoint_t c1, c2;
82725
82726 c1 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc);
82727 DUK_ASSERT(!(re_ctx->re_flags & DUK_RE_FLAG_IGNORE_CASE) ||
82728 c1 == duk_unicode_re_canonicalize_char(re_ctx->thr, c1)); /* canonicalized by compiler */
82729 c2 = duk__inp_get_cp(re_ctx, &sp);
82730 /* No need to check for c2 < 0 (end of input): because c1 >= 0, it
82731 * will fail the match below automatically and cause goto fail.
82732 */
82733#if 0
82734 if (c2 < 0) {
82735 goto fail;
82736 }
82737#endif
82738 DUK_ASSERT(c1 >= 0);
82739
82740 DUK_DDD(DUK_DDDPRINT("char match, c1=%ld, c2=%ld", (long) c1, (long) c2));
82741 if (c1 != c2) {
82742 goto fail;
82743 }
82744 break;
82745 }
82746 case DUK_REOP_PERIOD: {
82747 duk_codepoint_t c;
82748
82749 c = duk__inp_get_cp(re_ctx, &sp);
82750 if (c < 0 || duk_unicode_is_line_terminator(c)) {
82751 /* E5 Sections 15.10.2.8, 7.3 */
82752 goto fail;
82753 }
82754 break;
82755 }
82756 case DUK_REOP_RANGES:
82757 case DUK_REOP_INVRANGES: {
82758 duk_uint32_t n;
82759 duk_codepoint_t c;
82760 duk_small_int_t match;
82761
82762 n = duk__bc_get_u32(re_ctx, &pc);
82763 c = duk__inp_get_cp(re_ctx, &sp);
82764 if (c < 0) {
82765 goto fail;
82766 }
82767
82768 match = 0;
82769 while (n) {
82770 duk_codepoint_t r1, r2;
82771 r1 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc);
82772 r2 = (duk_codepoint_t) duk__bc_get_u32(re_ctx, &pc);
82773 DUK_DDD(DUK_DDDPRINT("matching ranges/invranges, n=%ld, r1=%ld, r2=%ld, c=%ld",
82774 (long) n, (long) r1, (long) r2, (long) c));
82775 if (c >= r1 && c <= r2) {
82776 /* Note: don't bail out early, we must read all the ranges from
82777 * bytecode. Another option is to skip them efficiently after
82778 * breaking out of here. Prefer smallest code.
82779 */
82780 match = 1;
82781 }
82782 n--;
82783 }
82784
82785 if (op == DUK_REOP_RANGES) {
82786 if (!match) {
82787 goto fail;
82788 }
82789 } else {
82790 DUK_ASSERT(op == DUK_REOP_INVRANGES);
82791 if (match) {
82792 goto fail;
82793 }
82794 }
82795 break;
82796 }
82797 case DUK_REOP_ASSERT_START: {
82798 duk_codepoint_t c;
82799
82800 if (sp <= re_ctx->input) {
82801 break;
82802 }
82803 if (!(re_ctx->re_flags & DUK_RE_FLAG_MULTILINE)) {
82804 goto fail;
82805 }
82806 c = duk__inp_get_prev_cp(re_ctx, sp);
82807 if (duk_unicode_is_line_terminator(c)) {
82808 /* E5 Sections 15.10.2.8, 7.3 */
82809 break;
82810 }
82811 goto fail;
82812 }
82813 case DUK_REOP_ASSERT_END: {
82814 duk_codepoint_t c;
82815 const duk_uint8_t *tmp_sp;
82816
82817 tmp_sp = sp;
82818 c = duk__inp_get_cp(re_ctx, &tmp_sp);
82819 if (c < 0) {
82820 break;
82821 }
82822 if (!(re_ctx->re_flags & DUK_RE_FLAG_MULTILINE)) {
82823 goto fail;
82824 }
82825 if (duk_unicode_is_line_terminator(c)) {
82826 /* E5 Sections 15.10.2.8, 7.3 */
82827 break;
82828 }
82829 goto fail;
82830 }
82831 case DUK_REOP_ASSERT_WORD_BOUNDARY:
82832 case DUK_REOP_ASSERT_NOT_WORD_BOUNDARY: {
82833 /*
82834 * E5 Section 15.10.2.6. The previous and current character
82835 * should -not- be canonicalized as they are now. However,
82836 * canonicalization does not affect the result of IsWordChar()
82837 * (which depends on Unicode characters never canonicalizing
82838 * into ASCII characters) so this does not matter.
82839 */
82840 duk_small_int_t w1, w2;
82841
82842 if (sp <= re_ctx->input) {
82843 w1 = 0; /* not a wordchar */
82844 } else {
82845 duk_codepoint_t c;
82846 c = duk__inp_get_prev_cp(re_ctx, sp);
82847 w1 = duk_unicode_re_is_wordchar(c);
82848 }
82849 if (sp >= re_ctx->input_end) {
82850 w2 = 0; /* not a wordchar */
82851 } else {
82852 const duk_uint8_t *tmp_sp = sp; /* dummy so sp won't get updated */
82853 duk_codepoint_t c;
82854 c = duk__inp_get_cp(re_ctx, &tmp_sp);
82855 w2 = duk_unicode_re_is_wordchar(c);
82856 }
82857
82858 if (op == DUK_REOP_ASSERT_WORD_BOUNDARY) {
82859 if (w1 == w2) {
82860 goto fail;
82861 }
82862 } else {
82863 DUK_ASSERT(op == DUK_REOP_ASSERT_NOT_WORD_BOUNDARY);
82864 if (w1 != w2) {
82865 goto fail;
82866 }
82867 }
82868 break;
82869 }
82870 case DUK_REOP_JUMP: {
82871 duk_int32_t skip;
82872
82873 skip = duk__bc_get_i32(re_ctx, &pc);
82874 pc += skip;
82875 break;
82876 }
82877 case DUK_REOP_SPLIT1: {
82878 /* split1: prefer direct execution (no jump) */
82879 const duk_uint8_t *sub_sp;
82880 duk_int32_t skip;
82881
82882 skip = duk__bc_get_i32(re_ctx, &pc);
82883 sub_sp = duk__match_regexp(re_ctx, pc, sp);
82884 if (sub_sp) {
82885 sp = sub_sp;
82886 goto match;
82887 }
82888 pc += skip;
82889 break;
82890 }
82891 case DUK_REOP_SPLIT2: {
82892 /* split2: prefer jump execution (not direct) */
82893 const duk_uint8_t *sub_sp;
82894 duk_int32_t skip;
82895
82896 skip = duk__bc_get_i32(re_ctx, &pc);
82897 sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
82898 if (sub_sp) {
82899 sp = sub_sp;
82900 goto match;
82901 }
82902 break;
82903 }
82904 case DUK_REOP_SQMINIMAL: {
82905 duk_uint32_t q, qmin, qmax;
82906 duk_int32_t skip;
82907 const duk_uint8_t *sub_sp;
82908
82909 qmin = duk__bc_get_u32(re_ctx, &pc);
82910 qmax = duk__bc_get_u32(re_ctx, &pc);
82911 skip = duk__bc_get_i32(re_ctx, &pc);
82912 DUK_DDD(DUK_DDDPRINT("minimal quantifier, qmin=%lu, qmax=%lu, skip=%ld",
82913 (unsigned long) qmin, (unsigned long) qmax, (long) skip));
82914
82915 q = 0;
82916 while (q <= qmax) {
82917 if (q >= qmin) {
82918 sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
82919 if (sub_sp) {
82920 sp = sub_sp;
82921 goto match;
82922 }
82923 }
82924 sub_sp = duk__match_regexp(re_ctx, pc, sp);
82925 if (!sub_sp) {
82926 break;
82927 }
82928 sp = sub_sp;
82929 q++;
82930 }
82931 goto fail;
82932 }
82933 case DUK_REOP_SQGREEDY: {
82934 duk_uint32_t q, qmin, qmax, atomlen;
82935 duk_int32_t skip;
82936 const duk_uint8_t *sub_sp;
82937
82938 qmin = duk__bc_get_u32(re_ctx, &pc);
82939 qmax = duk__bc_get_u32(re_ctx, &pc);
82940 atomlen = duk__bc_get_u32(re_ctx, &pc);
82941 skip = duk__bc_get_i32(re_ctx, &pc);
82942 DUK_DDD(DUK_DDDPRINT("greedy quantifier, qmin=%lu, qmax=%lu, atomlen=%lu, skip=%ld",
82943 (unsigned long) qmin, (unsigned long) qmax, (unsigned long) atomlen, (long) skip));
82944
82945 q = 0;
82946 while (q < qmax) {
82947 sub_sp = duk__match_regexp(re_ctx, pc, sp);
82948 if (!sub_sp) {
82949 break;
82950 }
82951 sp = sub_sp;
82952 q++;
82953 }
82954 while (q >= qmin) {
82955 sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
82956 if (sub_sp) {
82957 sp = sub_sp;
82958 goto match;
82959 }
82960 if (q == qmin) {
82961 break;
82962 }
82963
82964 /* Note: if atom were to contain e.g. captures, we would need to
82965 * re-match the atom to get correct captures. Simply quantifiers
82966 * do not allow captures in their atom now, so this is not an issue.
82967 */
82968
82969 DUK_DDD(DUK_DDDPRINT("greedy quantifier, backtrack %ld characters (atomlen)",
82970 (long) atomlen));
82971 sp = duk__inp_backtrack(re_ctx, &sp, (duk_uint_fast32_t) atomlen);
82972 q--;
82973 }
82974 goto fail;
82975 }
82976 case DUK_REOP_SAVE: {
82977 duk_uint32_t idx;
82978 const duk_uint8_t *old;
82979 const duk_uint8_t *sub_sp;
82980
82981 idx = duk__bc_get_u32(re_ctx, &pc);
82982 if (idx >= re_ctx->nsaved) {
82983 /* idx is unsigned, < 0 check is not necessary */
82984 DUK_D(DUK_DPRINT("internal error, regexp save index insane: idx=%ld", (long) idx));
82985 goto internal_error;
82986 }
82987 old = re_ctx->saved[idx];
82988 re_ctx->saved[idx] = sp;
82989 sub_sp = duk__match_regexp(re_ctx, pc, sp);
82990 if (sub_sp) {
82991 sp = sub_sp;
82992 goto match;
82993 }
82994 re_ctx->saved[idx] = old;
82995 goto fail;
82996 }
82997 case DUK_REOP_WIPERANGE: {
82998 /* Wipe capture range and save old values for backtracking.
82999 *
83000 * XXX: this typically happens with a relatively small idx_count.
83001 * It might be useful to handle cases where the count is small
83002 * (say <= 8) by saving the values in stack instead. This would
83003 * reduce memory churn and improve performance, at the cost of a
83004 * slightly higher code footprint.
83005 */
83006 duk_uint32_t idx_start, idx_count;
83007#if defined(DUK_USE_EXPLICIT_NULL_INIT)
83008 duk_uint32_t idx_end, idx;
83009#endif
83010 duk_uint8_t **range_save;
83011 const duk_uint8_t *sub_sp;
83012
83013 idx_start = duk__bc_get_u32(re_ctx, &pc);
83014 idx_count = duk__bc_get_u32(re_ctx, &pc);
83015 DUK_DDD(DUK_DDDPRINT("wipe saved range: start=%ld, count=%ld -> [%ld,%ld] (captures [%ld,%ld])",
83016 (long) idx_start, (long) idx_count,
83017 (long) idx_start, (long) (idx_start + idx_count - 1),
83018 (long) (idx_start / 2), (long) ((idx_start + idx_count - 1) / 2)));
83019 if (idx_start + idx_count > re_ctx->nsaved || idx_count == 0) {
83020 /* idx is unsigned, < 0 check is not necessary */
83021 DUK_D(DUK_DPRINT("internal error, regexp wipe indices insane: idx_start=%ld, idx_count=%ld",
83022 (long) idx_start, (long) idx_count));
83023 goto internal_error;
83024 }
83025 DUK_ASSERT(idx_count > 0);
83026
83027 duk_require_stack((duk_context *) re_ctx->thr, 1);
83028 range_save = (duk_uint8_t **) duk_push_fixed_buffer_nozero((duk_context *) re_ctx->thr,
83029 sizeof(duk_uint8_t *) * idx_count);
83030 DUK_ASSERT(range_save != NULL);
83031 DUK_MEMCPY(range_save, re_ctx->saved + idx_start, sizeof(duk_uint8_t *) * idx_count);
83032#if defined(DUK_USE_EXPLICIT_NULL_INIT)
83033 idx_end = idx_start + idx_count;
83034 for (idx = idx_start; idx < idx_end; idx++) {
83035 re_ctx->saved[idx] = NULL;
83036 }
83037#else
83038 DUK_MEMZERO((void *) (re_ctx->saved + idx_start), sizeof(duk_uint8_t *) * idx_count);
83039#endif
83040
83041 sub_sp = duk__match_regexp(re_ctx, pc, sp);
83042 if (sub_sp) {
83043 /* match: keep wiped/resaved values */
83044 DUK_DDD(DUK_DDDPRINT("match: keep wiped/resaved values [%ld,%ld] (captures [%ld,%ld])",
83045 (long) idx_start, (long) (idx_start + idx_count - 1),
83046 (long) (idx_start / 2), (long) ((idx_start + idx_count - 1) / 2)));
83047 duk_pop((duk_context *) re_ctx->thr);
83048 sp = sub_sp;
83049 goto match;
83050 }
83051
83052 /* fail: restore saves */
83053 DUK_DDD(DUK_DDDPRINT("fail: restore wiped/resaved values [%ld,%ld] (captures [%ld,%ld])",
83054 (long) idx_start, (long) (idx_start + idx_count - 1),
83055 (long) (idx_start / 2), (long) ((idx_start + idx_count - 1) / 2)));
83056 DUK_MEMCPY((void *) (re_ctx->saved + idx_start),
83057 (const void *) range_save,
83058 sizeof(duk_uint8_t *) * idx_count);
83059 duk_pop((duk_context *) re_ctx->thr);
83060 goto fail;
83061 }
83062 case DUK_REOP_LOOKPOS:
83063 case DUK_REOP_LOOKNEG: {
83064 /*
83065 * Needs a save of multiple saved[] entries depending on what range
83066 * may be overwritten. Because the regexp parser does no such analysis,
83067 * we currently save the entire saved array here. Lookaheads are thus
83068 * a bit expensive. Note that the saved array is not needed for just
83069 * the lookahead sub-match, but for the matching of the entire sequel.
83070 *
83071 * The temporary save buffer is pushed on to the valstack to handle
83072 * errors correctly. Each lookahead causes a C recursion and pushes
83073 * more stuff on the value stack. If the C recursion limit is less
83074 * than the value stack spare, there is no need to check the stack.
83075 * We do so regardless, just in case.
83076 */
83077
83078 duk_int32_t skip;
83079 duk_uint8_t **full_save;
83080 const duk_uint8_t *sub_sp;
83081
83082 DUK_ASSERT(re_ctx->nsaved > 0);
83083
83084 duk_require_stack((duk_context *) re_ctx->thr, 1);
83085 full_save = (duk_uint8_t **) duk_push_fixed_buffer_nozero((duk_context *) re_ctx->thr,
83086 sizeof(duk_uint8_t *) * re_ctx->nsaved);
83087 DUK_ASSERT(full_save != NULL);
83088 DUK_MEMCPY(full_save, re_ctx->saved, sizeof(duk_uint8_t *) * re_ctx->nsaved);
83089
83090 skip = duk__bc_get_i32(re_ctx, &pc);
83091 sub_sp = duk__match_regexp(re_ctx, pc, sp);
83092 if (op == DUK_REOP_LOOKPOS) {
83093 if (!sub_sp) {
83094 goto lookahead_fail;
83095 }
83096 } else {
83097 if (sub_sp) {
83098 goto lookahead_fail;
83099 }
83100 }
83101 sub_sp = duk__match_regexp(re_ctx, pc + skip, sp);
83102 if (sub_sp) {
83103 /* match: keep saves */
83104 duk_pop((duk_context *) re_ctx->thr);
83105 sp = sub_sp;
83106 goto match;
83107 }
83108
83109 /* fall through */
83110
83111 lookahead_fail:
83112 /* fail: restore saves */
83113 DUK_MEMCPY((void *) re_ctx->saved,
83114 (const void *) full_save,
83115 sizeof(duk_uint8_t *) * re_ctx->nsaved);
83116 duk_pop((duk_context *) re_ctx->thr);
83117 goto fail;
83118 }
83119 case DUK_REOP_BACKREFERENCE: {
83120 /*
83121 * Byte matching for back-references would be OK in case-
83122 * sensitive matching. In case-insensitive matching we need
83123 * to canonicalize characters, so back-reference matching needs
83124 * to be done with codepoints instead. So, we just decode
83125 * everything normally here, too.
83126 *
83127 * Note: back-reference index which is 0 or higher than
83128 * NCapturingParens (= number of capturing parens in the
83129 * -entire- regexp) is a compile time error. However, a
83130 * backreference referring to a valid capture which has
83131 * not matched anything always succeeds! See E5 Section
83132 * 15.10.2.9, step 5, sub-step 3.
83133 */
83134 duk_uint32_t idx;
83135 const duk_uint8_t *p;
83136
83137 idx = duk__bc_get_u32(re_ctx, &pc);
83138 idx = idx << 1; /* backref n -> saved indices [n*2, n*2+1] */
83139 if (idx < 2 || idx + 1 >= re_ctx->nsaved) {
83140 /* regexp compiler should catch these */
83141 DUK_D(DUK_DPRINT("internal error, backreference index insane"));
83142 goto internal_error;
83143 }
83144 if (!re_ctx->saved[idx] || !re_ctx->saved[idx+1]) {
83145 /* capture is 'undefined', always matches! */
83146 DUK_DDD(DUK_DDDPRINT("backreference: saved[%ld,%ld] not complete, always match",
83147 (long) idx, (long) (idx + 1)));
83148 break;
83149 }
83150 DUK_DDD(DUK_DDDPRINT("backreference: match saved[%ld,%ld]", (long) idx, (long) (idx + 1)));
83151
83152 p = re_ctx->saved[idx];
83153 while (p < re_ctx->saved[idx+1]) {
83154 duk_codepoint_t c1, c2;
83155
83156 /* Note: not necessary to check p against re_ctx->input_end:
83157 * the memory access is checked by duk__inp_get_cp(), while
83158 * valid compiled regexps cannot write a saved[] entry
83159 * which points to outside the string.
83160 */
83161 c1 = duk__inp_get_cp(re_ctx, &p);
83162 DUK_ASSERT(c1 >= 0);
83163 c2 = duk__inp_get_cp(re_ctx, &sp);
83164 /* No need for an explicit c2 < 0 check: because c1 >= 0,
83165 * the comparison will always fail if c2 < 0.
83166 */
83167#if 0
83168 if (c2 < 0) {
83169 goto fail;
83170 }
83171#endif
83172 if (c1 != c2) {
83173 goto fail;
83174 }
83175 }
83176 break;
83177 }
83178 default: {
83179 DUK_D(DUK_DPRINT("internal error, regexp opcode error: %ld", (long) op));
83180 goto internal_error;
83181 }
83182 }
83183 }
83184
83185 match:
83186 re_ctx->recursion_depth--;
83187 return sp;
83188
83189 fail:
83190 re_ctx->recursion_depth--;
83191 return NULL;
83192
83193 internal_error:
83194 DUK_ERROR_INTERNAL(re_ctx->thr);
83195 return NULL; /* never here */
83196}
83197
83198/*
83199 * Exposed matcher function which provides the semantics of RegExp.prototype.exec().
83200 *
83201 * RegExp.prototype.test() has the same semantics as exec() but does not return the
83202 * result object (which contains the matching string and capture groups). Currently
83203 * there is no separate test() helper, so a temporary result object is created and
83204 * discarded if test() is needed. This is intentional, to save code space.
83205 *
83206 * Input stack: [ ... re_obj input ]
83207 * Output stack: [ ... result ]
83208 */
83209
83210DUK_LOCAL void duk__regexp_match_helper(duk_hthread *thr, duk_small_int_t force_global) {
83211 duk_context *ctx = (duk_context *) thr;
83212 duk_re_matcher_ctx re_ctx;
83213 duk_hobject *h_regexp;
83214 duk_hstring *h_bytecode;
83215 duk_hstring *h_input;
83216 duk_uint8_t *p_buf;
83217 const duk_uint8_t *pc;
83218 const duk_uint8_t *sp;
83219 duk_small_int_t match = 0;
83220 duk_small_int_t global;
83221 duk_uint_fast32_t i;
83222 double d;
83223 duk_uint32_t char_offset;
83224
83225 DUK_ASSERT(thr != NULL);
83226 DUK_ASSERT(ctx != NULL);
83227
83228 DUK_DD(DUK_DDPRINT("regexp match: regexp=%!T, input=%!T",
83229 (duk_tval *) duk_get_tval(ctx, -2),
83230 (duk_tval *) duk_get_tval(ctx, -1)));
83231
83232 /*
83233 * Regexp instance check, bytecode check, input coercion.
83234 *
83235 * See E5 Section 15.10.6.
83236 */
83237
83238 /* TypeError if wrong; class check, see E5 Section 15.10.6 */
83239 h_regexp = duk_require_hobject_with_class(ctx, -2, DUK_HOBJECT_CLASS_REGEXP);
83240 DUK_ASSERT(h_regexp != NULL);
83241 DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_regexp) == DUK_HOBJECT_CLASS_REGEXP);
83242 DUK_UNREF(h_regexp);
83243
83244 h_input = duk_to_hstring(ctx, -1);
83245 DUK_ASSERT(h_input != NULL);
83246
83247 duk_get_prop_stridx_short(ctx, -2, DUK_STRIDX_INT_BYTECODE); /* [ ... re_obj input ] -> [ ... re_obj input bc ] */
83248 h_bytecode = duk_require_hstring(ctx, -1); /* no regexp instance should exist without a non-configurable bytecode property */
83249 DUK_ASSERT(h_bytecode != NULL);
83250
83251 /*
83252 * Basic context initialization.
83253 *
83254 * Some init values are read from the bytecode header
83255 * whose format is (UTF-8 codepoints):
83256 *
83257 * uint flags
83258 * uint nsaved (even, 2n+2 where n = num captures)
83259 */
83260
83261 /* [ ... re_obj input bc ] */
83262
83263 DUK_MEMZERO(&re_ctx, sizeof(re_ctx));
83264
83265 re_ctx.thr = thr;
83266 re_ctx.input = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_input);
83267 re_ctx.input_end = re_ctx.input + DUK_HSTRING_GET_BYTELEN(h_input);
83268 re_ctx.bytecode = (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h_bytecode);
83269 re_ctx.bytecode_end = re_ctx.bytecode + DUK_HSTRING_GET_BYTELEN(h_bytecode);
83270 re_ctx.saved = NULL;
83271 re_ctx.recursion_limit = DUK_USE_REGEXP_EXECUTOR_RECLIMIT;
83272 re_ctx.steps_limit = DUK_RE_EXECUTE_STEPS_LIMIT;
83273
83274 /* read header */
83275 pc = re_ctx.bytecode;
83276 re_ctx.re_flags = duk__bc_get_u32(&re_ctx, &pc);
83277 re_ctx.nsaved = duk__bc_get_u32(&re_ctx, &pc);
83278 re_ctx.bytecode = pc;
83279
83280 DUK_ASSERT(DUK_RE_FLAG_GLOBAL < 0x10000UL); /* must fit into duk_small_int_t */
83281 global = (duk_small_int_t) (force_global | (re_ctx.re_flags & DUK_RE_FLAG_GLOBAL));
83282
83283 DUK_ASSERT(re_ctx.nsaved >= 2);
83284 DUK_ASSERT((re_ctx.nsaved % 2) == 0);
83285
83286 p_buf = (duk_uint8_t *) duk_push_fixed_buffer(ctx, sizeof(duk_uint8_t *) * re_ctx.nsaved); /* rely on zeroing */
83287 DUK_UNREF(p_buf);
83288 re_ctx.saved = (const duk_uint8_t **) duk_get_buffer(ctx, -1, NULL);
83289 DUK_ASSERT(re_ctx.saved != NULL);
83290
83291 /* [ ... re_obj input bc saved_buf ] */
83292
83293#if defined(DUK_USE_EXPLICIT_NULL_INIT)
83294 for (i = 0; i < re_ctx.nsaved; i++) {
83295 re_ctx.saved[i] = (duk_uint8_t *) NULL;
83296 }
83297#elif defined(DUK_USE_ZERO_BUFFER_DATA)
83298 /* buffer is automatically zeroed */
83299#else
83300 DUK_MEMZERO((void *) p_buf, sizeof(duk_uint8_t *) * re_ctx.nsaved);
83301#endif
83302
83303 DUK_DDD(DUK_DDDPRINT("regexp ctx initialized, flags=0x%08lx, nsaved=%ld, recursion_limit=%ld, steps_limit=%ld",
83304 (unsigned long) re_ctx.re_flags, (long) re_ctx.nsaved, (long) re_ctx.recursion_limit,
83305 (long) re_ctx.steps_limit));
83306
83307 /*
83308 * Get starting character offset for match, and initialize 'sp' based on it.
83309 *
83310 * Note: lastIndex is non-configurable so it must be present (we check the
83311 * internal class of the object above, so we know it is). User code can set
83312 * its value to an arbitrary (garbage) value though; E5 requires that lastIndex
83313 * be coerced to a number before using. The code below works even if the
83314 * property is missing: the value will then be coerced to zero.
83315 *
83316 * Note: lastIndex may be outside Uint32 range even after ToInteger() coercion.
83317 * For instance, ToInteger(+Infinity) = +Infinity. We track the match offset
83318 * as an integer, but pre-check it to be inside the 32-bit range before the loop.
83319 * If not, the check in E5 Section 15.10.6.2, step 9.a applies.
83320 */
83321
83322 /* XXX: lastIndex handling produces a lot of asm */
83323
83324 /* [ ... re_obj input bc saved_buf ] */
83325
83326 duk_get_prop_stridx_short(ctx, -4, DUK_STRIDX_LAST_INDEX); /* -> [ ... re_obj input bc saved_buf lastIndex ] */
83327 (void) duk_to_int(ctx, -1); /* ToInteger(lastIndex) */
83328 d = duk_get_number(ctx, -1); /* integer, but may be +/- Infinite, +/- zero (not NaN, though) */
83329 duk_pop(ctx);
83330
83331 if (global) {
83332 if (d < 0.0 || d > (double) DUK_HSTRING_GET_CHARLEN(h_input)) {
83333 /* match fail */
83334 char_offset = 0; /* not really necessary */
83335 DUK_ASSERT(match == 0);
83336 goto match_over;
83337 }
83338 char_offset = (duk_uint32_t) d;
83339 } else {
83340 /* lastIndex must be ignored for non-global regexps, but get the
83341 * value for (theoretical) side effects. No side effects can
83342 * really occur, because lastIndex is a normal property and is
83343 * always non-configurable for RegExp instances.
83344 */
83345 char_offset = (duk_uint32_t) 0;
83346 }
83347
83348 sp = re_ctx.input + duk_heap_strcache_offset_char2byte(thr, h_input, char_offset);
83349
83350 /*
83351 * Match loop.
83352 *
83353 * Try matching at different offsets until match found or input exhausted.
83354 */
83355
83356 /* [ ... re_obj input bc saved_buf ] */
83357
83358 DUK_ASSERT(match == 0);
83359
83360 for (;;) {
83361 /* char offset in [0, h_input->clen] (both ends inclusive), checked before entry */
83362 DUK_ASSERT_DISABLE(char_offset >= 0);
83363 DUK_ASSERT(char_offset <= DUK_HSTRING_GET_CHARLEN(h_input));
83364
83365 /* Note: ctx.steps is intentionally not reset, it applies to the entire unanchored match */
83366 DUK_ASSERT(re_ctx.recursion_depth == 0);
83367
83368 DUK_DDD(DUK_DDDPRINT("attempt match at char offset %ld; %p [%p,%p]",
83369 (long) char_offset, (const void *) sp,
83370 (const void *) re_ctx.input, (const void *) re_ctx.input_end));
83371
83372 /*
83373 * Note:
83374 *
83375 * - duk__match_regexp() is required not to longjmp() in ordinary "non-match"
83376 * conditions; a longjmp() will terminate the entire matching process.
83377 *
83378 * - Clearing saved[] is not necessary because backtracking does it
83379 *
83380 * - Backtracking also rewinds ctx.recursion back to zero, unless an
83381 * internal/limit error occurs (which causes a longjmp())
83382 *
83383 * - If we supported anchored matches, we would break out here
83384 * unconditionally; however, Ecmascript regexps don't have anchored
83385 * matches. It might make sense to implement a fast bail-out if
83386 * the regexp begins with '^' and sp is not 0: currently we'll just
83387 * run through the entire input string, trivially failing the match
83388 * at every non-zero offset.
83389 */
83390
83391 if (duk__match_regexp(&re_ctx, re_ctx.bytecode, sp) != NULL) {
83392 DUK_DDD(DUK_DDDPRINT("match at offset %ld", (long) char_offset));
83393 match = 1;
83394 break;
83395 }
83396
83397 /* advance by one character (code point) and one char_offset */
83398 char_offset++;
83399 if (char_offset > DUK_HSTRING_GET_CHARLEN(h_input)) {
83400 /*
83401 * Note:
83402 *
83403 * - Intentionally attempt (empty) match at char_offset == k_input->clen
83404 *
83405 * - Negative char_offsets have been eliminated and char_offset is duk_uint32_t
83406 * -> no need or use for a negative check
83407 */
83408
83409 DUK_DDD(DUK_DDDPRINT("no match after trying all sp offsets"));
83410 break;
83411 }
83412
83413 /* avoid calling at end of input, will DUK_ERROR (above check suffices to avoid this) */
83414 (void) duk__utf8_advance(thr, &sp, re_ctx.input, re_ctx.input_end, (duk_uint_fast32_t) 1);
83415 }
83416
83417 match_over:
83418
83419 /*
83420 * Matching complete, create result array or return a 'null'. Update lastIndex
83421 * if necessary. See E5 Section 15.10.6.2.
83422 *
83423 * Because lastIndex is a character (not byte) offset, we need the character
83424 * length of the match which we conveniently get as a side effect of interning
83425 * the matching substring (0th index of result array).
83426 *
83427 * saved[0] start pointer (~ byte offset) of current match
83428 * saved[1] end pointer (~ byte offset) of current match (exclusive)
83429 * char_offset start character offset of current match (-> .index of result)
83430 * char_end_offset end character offset (computed below)
83431 */
83432
83433 /* [ ... re_obj input bc saved_buf ] */
83434
83435 if (match) {
83436#if defined(DUK_USE_ASSERTIONS)
83437 duk_hobject *h_res;
83438#endif
83439 duk_uint32_t char_end_offset = 0;
83440
83441 DUK_DDD(DUK_DDDPRINT("regexp matches at char_offset %ld", (long) char_offset));
83442
83443 DUK_ASSERT(re_ctx.nsaved >= 2); /* must have start and end */
83444 DUK_ASSERT((re_ctx.nsaved % 2) == 0); /* and even number */
83445
83446 /* XXX: Array size is known before and (2 * re_ctx.nsaved) but not taken
83447 * advantage of now. The array is not compacted either, as regexp match
83448 * objects are usually short lived.
83449 */
83450
83451 duk_push_array(ctx);
83452
83453#if defined(DUK_USE_ASSERTIONS)
83454 h_res = duk_require_hobject(ctx, -1);
83455 DUK_ASSERT(DUK_HOBJECT_HAS_EXTENSIBLE(h_res));
83456 DUK_ASSERT(DUK_HOBJECT_HAS_EXOTIC_ARRAY(h_res));
83457 DUK_ASSERT(DUK_HOBJECT_GET_CLASS_NUMBER(h_res) == DUK_HOBJECT_CLASS_ARRAY);
83458#endif
83459
83460 /* [ ... re_obj input bc saved_buf res_obj ] */
83461
83462 duk_push_u32(ctx, char_offset);
83463 duk_xdef_prop_stridx_short_wec(ctx, -2, DUK_STRIDX_INDEX);
83464
83465 duk_dup_m4(ctx);
83466 duk_xdef_prop_stridx_short_wec(ctx, -2, DUK_STRIDX_INPUT);
83467
83468 for (i = 0; i < re_ctx.nsaved; i += 2) {
83469 /* Captures which are undefined have NULL pointers and are returned
83470 * as 'undefined'. The same is done when saved[] pointers are insane
83471 * (this should, of course, never happen in practice).
83472 */
83473 if (re_ctx.saved[i] && re_ctx.saved[i + 1] && re_ctx.saved[i + 1] >= re_ctx.saved[i]) {
83474 duk_push_lstring(ctx,
83475 (const char *) re_ctx.saved[i],
83476 (duk_size_t) (re_ctx.saved[i+1] - re_ctx.saved[i]));
83477 if (i == 0) {
83478 /* Assumes that saved[0] and saved[1] are always
83479 * set by regexp bytecode (if not, char_end_offset
83480 * will be zero). Also assumes clen reflects the
83481 * correct char length.
83482 */
83483 char_end_offset = char_offset + (duk_uint32_t) duk_get_length(ctx, -1); /* add charlen */
83484 }
83485 } else {
83486 duk_push_undefined(ctx);
83487 }
83488
83489 /* [ ... re_obj input bc saved_buf res_obj val ] */
83490 duk_put_prop_index(ctx, -2, i / 2);
83491 }
83492
83493 /* [ ... re_obj input bc saved_buf res_obj ] */
83494
83495 /* NB: 'length' property is automatically updated by the array setup loop */
83496
83497 if (global) {
83498 /* global regexp: lastIndex updated on match */
83499 duk_push_u32(ctx, char_end_offset);
83500 duk_put_prop_stridx_short(ctx, -6, DUK_STRIDX_LAST_INDEX);
83501 } else {
83502 /* non-global regexp: lastIndex never updated on match */
83503 ;
83504 }
83505 } else {
83506 /*
83507 * No match, E5 Section 15.10.6.2, step 9.a.i - 9.a.ii apply, regardless
83508 * of 'global' flag of the RegExp. In particular, if lastIndex is invalid
83509 * initially, it is reset to zero.
83510 */
83511
83512 DUK_DDD(DUK_DDDPRINT("regexp does not match"));
83513
83514 duk_push_null(ctx);
83515
83516 /* [ ... re_obj input bc saved_buf res_obj ] */
83517
83518 duk_push_int(ctx, 0);
83519 duk_put_prop_stridx_short(ctx, -6, DUK_STRIDX_LAST_INDEX);
83520 }
83521
83522 /* [ ... re_obj input bc saved_buf res_obj ] */
83523
83524 duk_insert(ctx, -5);
83525
83526 /* [ ... res_obj re_obj input bc saved_buf ] */
83527
83528 duk_pop_n(ctx, 4);
83529
83530 /* [ ... res_obj ] */
83531
83532 /* XXX: these last tricks are unnecessary if the function is made
83533 * a genuine native function.
83534 */
83535}
83536
83537DUK_INTERNAL void duk_regexp_match(duk_hthread *thr) {
83538 duk__regexp_match_helper(thr, 0 /*force_global*/);
83539}
83540
83541/* This variant is needed by String.prototype.split(); it needs to perform
83542 * global-style matching on a cloned RegExp which is potentially non-global.
83543 */
83544DUK_INTERNAL void duk_regexp_match_force_global(duk_hthread *thr) {
83545 duk__regexp_match_helper(thr, 1 /*force_global*/);
83546}
83547
83548#else /* DUK_USE_REGEXP_SUPPORT */
83549
83550/* regexp support disabled */
83551
83552#endif /* DUK_USE_REGEXP_SUPPORT */
83553/*
83554 * Self tests to ensure execution environment is sane. Intended to catch
83555 * compiler/platform problems which cannot be detected at compile time.
83556 */
83557
83558/* #include duk_internal.h -> already included */
83559
83560#if defined(DUK_USE_SELF_TESTS)
83561
83562/*
83563 * Unions and structs for self tests
83564 */
83565
83566typedef union {
83567 double d;
83568 duk_uint8_t x[8];
83569} duk__test_double_union;
83570
83571/* Self test failed. Expects a local variable 'error_count' to exist. */
83572#define DUK__FAILED(msg) do { \
83573 DUK_D(DUK_DPRINT("self test failed: " #msg " at " DUK_FILE_MACRO ":" DUK_MACRO_STRINGIFY(DUK_LINE_MACRO))); \
83574 error_count++; \
83575 } while (0)
83576
83577#define DUK__DBLUNION_CMP_TRUE(a,b) do { \
83578 if (DUK_MEMCMP((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) != 0) { \
83579 DUK__FAILED("double union compares false (expected true)"); \
83580 } \
83581 } while (0)
83582
83583#define DUK__DBLUNION_CMP_FALSE(a,b) do { \
83584 if (DUK_MEMCMP((const void *) (a), (const void *) (b), sizeof(duk__test_double_union)) == 0) { \
83585 DUK__FAILED("double union compares true (expected false)"); \
83586 } \
83587 } while (0)
83588
83589typedef union {
83590 duk_uint32_t i;
83591 duk_uint8_t x[8];
83592} duk__test_u32_union;
83593
83594#if defined(DUK_USE_INTEGER_LE)
83595#define DUK__U32_INIT(u, a, b, c, d) do { \
83596 (u)->x[0] = (d); (u)->x[1] = (c); (u)->x[2] = (b); (u)->x[3] = (a); \
83597 } while (0)
83598#elif defined(DUK_USE_INTEGER_ME)
83599#error integer mixed endian not supported now
83600#elif defined(DUK_USE_INTEGER_BE)
83601#define DUK__U32_INIT(u, a, b, c, d) do { \
83602 (u)->x[0] = (a); (u)->x[1] = (b); (u)->x[2] = (c); (u)->x[3] = (d); \
83603 } while (0)
83604#else
83605#error unknown integer endianness
83606#endif
83607
83608#if defined(DUK_USE_DOUBLE_LE)
83609#define DUK__DOUBLE_INIT(u, a, b, c, d, e, f, g, h) do { \
83610 (u)->x[0] = (h); (u)->x[1] = (g); (u)->x[2] = (f); (u)->x[3] = (e); \
83611 (u)->x[4] = (d); (u)->x[5] = (c); (u)->x[6] = (b); (u)->x[7] = (a); \
83612 } while (0)
83613#define DUK__DOUBLE_COMPARE(u, a, b, c, d, e, f, g, h) \
83614 ((u)->x[0] == (h) && (u)->x[1] == (g) && (u)->x[2] == (f) && (u)->x[3] == (e) && \
83615 (u)->x[4] == (d) && (u)->x[5] == (c) && (u)->x[6] == (b) && (u)->x[7] == (a))
83616#elif defined(DUK_USE_DOUBLE_ME)
83617#define DUK__DOUBLE_INIT(u, a, b, c, d, e, f, g, h) do { \
83618 (u)->x[0] = (d); (u)->x[1] = (c); (u)->x[2] = (b); (u)->x[3] = (a); \
83619 (u)->x[4] = (h); (u)->x[5] = (g); (u)->x[6] = (f); (u)->x[7] = (e); \
83620 } while (0)
83621#define DUK__DOUBLE_COMPARE(u, a, b, c, d, e, f, g, h) \
83622 ((u)->x[0] == (d) && (u)->x[1] == (c) && (u)->x[2] == (b) && (u)->x[3] == (a) && \
83623 (u)->x[4] == (h) && (u)->x[5] == (g) && (u)->x[6] == (f) && (u)->x[7] == (e))
83624#elif defined(DUK_USE_DOUBLE_BE)
83625#define DUK__DOUBLE_INIT(u, a, b, c, d, e, f, g, h) do { \
83626 (u)->x[0] = (a); (u)->x[1] = (b); (u)->x[2] = (c); (u)->x[3] = (d); \
83627 (u)->x[4] = (e); (u)->x[5] = (f); (u)->x[6] = (g); (u)->x[7] = (h); \
83628 } while (0)
83629#define DUK__DOUBLE_COMPARE(u, a, b, c, d, e, f, g, h) \
83630 ((u)->x[0] == (a) && (u)->x[1] == (b) && (u)->x[2] == (c) && (u)->x[3] == (d) && \
83631 (u)->x[4] == (e) && (u)->x[5] == (f) && (u)->x[6] == (g) && (u)->x[7] == (h))
83632#else
83633#error unknown double endianness
83634#endif
83635
83636/*
83637 * Various sanity checks for typing
83638 */
83639
83640DUK_LOCAL duk_uint_t duk__selftest_types(void) {
83641 duk_uint_t error_count = 0;
83642
83643 if (!(sizeof(duk_int8_t) == 1 &&
83644 sizeof(duk_uint8_t) == 1 &&
83645 sizeof(duk_int16_t) == 2 &&
83646 sizeof(duk_uint16_t) == 2 &&
83647 sizeof(duk_int32_t) == 4 &&
83648 sizeof(duk_uint32_t) == 4)) {
83649 DUK__FAILED("duk_(u)int{8,16,32}_t size");
83650 }
83651#if defined(DUK_USE_64BIT_OPS)
83652 if (!(sizeof(duk_int64_t) == 8 &&
83653 sizeof(duk_uint64_t) == 8)) {
83654 DUK__FAILED("duk_(u)int64_t size");
83655 }
83656#endif
83657
83658 if (!(sizeof(duk_size_t) >= sizeof(duk_uint_t))) {
83659 /* Some internal code now assumes that all duk_uint_t values
83660 * can be expressed with a duk_size_t.
83661 */
83662 DUK__FAILED("duk_size_t is smaller than duk_uint_t");
83663 }
83664 if (!(sizeof(duk_int_t) >= 4)) {
83665 DUK__FAILED("duk_int_t is not 32 bits");
83666 }
83667
83668 return error_count;
83669}
83670
83671/*
83672 * Packed tval sanity
83673 */
83674
83675DUK_LOCAL duk_uint_t duk__selftest_packed_tval(void) {
83676 duk_uint_t error_count = 0;
83677
83678#if defined(DUK_USE_PACKED_TVAL)
83679 if (sizeof(void *) > 4) {
83680 DUK__FAILED("packed duk_tval in use but sizeof(void *) > 4");
83681 }
83682#endif
83683
83684 return error_count;
83685}
83686
83687/*
83688 * Two's complement arithmetic.
83689 */
83690
83691DUK_LOCAL duk_uint_t duk__selftest_twos_complement(void) {
83692 duk_uint_t error_count = 0;
83693 volatile int test;
83694 test = -1;
83695
83696 /* Note that byte order doesn't affect this test: all bytes in
83697 * 'test' will be 0xFF for two's complement.
83698 */
83699 if (((volatile duk_uint8_t *) &test)[0] != (duk_uint8_t) 0xff) {
83700 DUK__FAILED("two's complement arithmetic");
83701 }
83702
83703 return error_count;
83704}
83705
83706/*
83707 * Byte order. Important to self check, because on some exotic platforms
83708 * there is no actual detection but rather assumption based on platform
83709 * defines.
83710 */
83711
83712DUK_LOCAL duk_uint_t duk__selftest_byte_order(void) {
83713 duk_uint_t error_count = 0;
83714 duk__test_u32_union u1;
83715 duk__test_double_union u2;
83716
83717 /*
83718 * >>> struct.pack('>d', 102030405060).encode('hex')
83719 * '4237c17c6dc40000'
83720 */
83721
83722 DUK__U32_INIT(&u1, 0xde, 0xad, 0xbe, 0xef);
83723 DUK__DOUBLE_INIT(&u2, 0x42, 0x37, 0xc1, 0x7c, 0x6d, 0xc4, 0x00, 0x00);
83724
83725 if (u1.i != (duk_uint32_t) 0xdeadbeefUL) {
83726 DUK__FAILED("duk_uint32_t byte order");
83727 }
83728
83729 if (u2.d != (double) 102030405060.0) {
83730 DUK__FAILED("double byte order");
83731 }
83732
83733 return error_count;
83734}
83735
83736/*
83737 * DUK_BSWAP macros
83738 */
83739
83740DUK_LOCAL duk_uint_t duk__selftest_bswap_macros(void) {
83741 duk_uint_t error_count = 0;
83742 duk_uint32_t x32;
83743 duk_uint16_t x16;
83745 duk_double_t du_diff;
83746
83747 x16 = 0xbeefUL;
83748 x16 = DUK_BSWAP16(x16);
83749 if (x16 != (duk_uint16_t) 0xefbeUL) {
83750 DUK__FAILED("DUK_BSWAP16");
83751 }
83752
83753 x32 = 0xdeadbeefUL;
83754 x32 = DUK_BSWAP32(x32);
83755 if (x32 != (duk_uint32_t) 0xefbeaddeUL) {
83756 DUK__FAILED("DUK_BSWAP32");
83757 }
83758
83759 /* >>> struct.unpack('>d', '4000112233445566'.decode('hex'))
83760 * (2.008366013071895,)
83761 */
83762
83763 du.uc[0] = 0x40; du.uc[1] = 0x00; du.uc[2] = 0x11; du.uc[3] = 0x22;
83764 du.uc[4] = 0x33; du.uc[5] = 0x44; du.uc[6] = 0x55; du.uc[7] = 0x66;
83765 DUK_DBLUNION_DOUBLE_NTOH(&du);
83766 du_diff = du.d - 2.008366013071895;
83767#if 0
83768 DUK_D(DUK_DPRINT("du_diff: %lg\n", (double) du_diff));
83769#endif
83770 if (du_diff > 1e-15) {
83771 /* Allow very small lenience because some compilers won't parse
83772 * exact IEEE double constants (happened in matrix testing with
83773 * Linux gcc-4.8 -m32 at least).
83774 */
83775#if 0
83776 DUK_D(DUK_DPRINT("Result of DUK_DBLUNION_DOUBLE_NTOH: %02x %02x %02x %02x %02x %02x %02x %02x\n",
83777 (unsigned int) du.uc[0], (unsigned int) du.uc[1],
83778 (unsigned int) du.uc[2], (unsigned int) du.uc[3],
83779 (unsigned int) du.uc[4], (unsigned int) du.uc[5],
83780 (unsigned int) du.uc[6], (unsigned int) du.uc[7]));
83781#endif
83782 DUK__FAILED("DUK_DBLUNION_DOUBLE_NTOH");
83783 }
83784
83785 return error_count;
83786}
83787
83788/*
83789 * Basic double / byte union memory layout.
83790 */
83791
83792DUK_LOCAL duk_uint_t duk__selftest_double_union_size(void) {
83793 duk_uint_t error_count = 0;
83794
83795 if (sizeof(duk__test_double_union) != 8) {
83796 DUK__FAILED("invalid union size");
83797 }
83798
83799 return error_count;
83800}
83801
83802/*
83803 * Union aliasing, see misc/clang_aliasing.c.
83804 */
83805
83806DUK_LOCAL duk_uint_t duk__selftest_double_aliasing(void) {
83807 /* This testcase fails when Emscripten-generated code runs on Firefox.
83808 * It's not an issue because the failure should only affect packed
83809 * duk_tval representation, which is not used with Emscripten.
83810 */
83811#if defined(DUK_USE_PACKED_TVAL)
83812 duk_uint_t error_count = 0;
83813 duk__test_double_union a, b;
83814
83815 /* Test signaling NaN and alias assignment in all endianness combinations.
83816 */
83817
83818 /* little endian */
83819 a.x[0] = 0x11; a.x[1] = 0x22; a.x[2] = 0x33; a.x[3] = 0x44;
83820 a.x[4] = 0x00; a.x[5] = 0x00; a.x[6] = 0xf1; a.x[7] = 0xff;
83821 b = a;
83822 DUK__DBLUNION_CMP_TRUE(&a, &b);
83823
83824 /* big endian */
83825 a.x[0] = 0xff; a.x[1] = 0xf1; a.x[2] = 0x00; a.x[3] = 0x00;
83826 a.x[4] = 0x44; a.x[5] = 0x33; a.x[6] = 0x22; a.x[7] = 0x11;
83827 b = a;
83828 DUK__DBLUNION_CMP_TRUE(&a, &b);
83829
83830 /* mixed endian */
83831 a.x[0] = 0x00; a.x[1] = 0x00; a.x[2] = 0xf1; a.x[3] = 0xff;
83832 a.x[4] = 0x11; a.x[5] = 0x22; a.x[6] = 0x33; a.x[7] = 0x44;
83833 b = a;
83834 DUK__DBLUNION_CMP_TRUE(&a, &b);
83835
83836 return error_count;
83837#else
83838 DUK_D(DUK_DPRINT("skip double aliasing self test when duk_tval is not packed"));
83839 return 0;
83840#endif
83841}
83842
83843/*
83844 * Zero sign, see misc/tcc_zerosign2.c.
83845 */
83846
83847DUK_LOCAL duk_uint_t duk__selftest_double_zero_sign(void) {
83848 duk_uint_t error_count = 0;
83849 duk__test_double_union a, b;
83850
83851 a.d = 0.0;
83852 b.d = -a.d;
83853 DUK__DBLUNION_CMP_FALSE(&a, &b);
83854
83855 return error_count;
83856}
83857
83858/*
83859 * Rounding mode: Duktape assumes round-to-nearest, check that this is true.
83860 * If we had C99 fenv.h we could check that fegetround() == FE_TONEAREST,
83861 * but we don't want to rely on that header; and even if we did, it's good
83862 * to ensure the rounding actually works.
83863 */
83864
83865DUK_LOCAL duk_uint_t duk__selftest_double_rounding(void) {
83866 duk_uint_t error_count = 0;
83867 duk__test_double_union a, b, c;
83868
83869#if 0
83870 /* Include <fenv.h> and test manually; these trigger failures: */
83871 fesetround(FE_UPWARD);
83872 fesetround(FE_DOWNWARD);
83873 fesetround(FE_TOWARDZERO);
83874
83875 /* This is the default and passes. */
83876 fesetround(FE_TONEAREST);
83877#endif
83878
83879 /* Rounding tests check that none of the other modes (round to
83880 * +Inf, round to -Inf, round to zero) can be active:
83881 * http://www.gnu.org/software/libc/manual/html_node/Rounding.html
83882 */
83883
83884 /* 1.0 + 2^(-53): result is midway between 1.0 and 1.0 + ulp.
83885 * Round to nearest: 1.0
83886 * Round to +Inf: 1.0 + ulp
83887 * Round to -Inf: 1.0
83888 * Round to zero: 1.0
83889 * => Correct result eliminates round to +Inf.
83890 */
83891 DUK__DOUBLE_INIT(&a, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
83892 DUK__DOUBLE_INIT(&b, 0x3c, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
83893 DUK_MEMSET((void *) &c, 0, sizeof(c));
83894 c.d = a.d + b.d;
83895 if (!DUK__DOUBLE_COMPARE(&c, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)) {
83896 DUK_D(DUK_DPRINT("broken result (native endiannesss): %02x %02x %02x %02x %02x %02x %02x %02x",
83897 (unsigned int) c.x[0], (unsigned int) c.x[1],
83898 (unsigned int) c.x[2], (unsigned int) c.x[3],
83899 (unsigned int) c.x[4], (unsigned int) c.x[5],
83900 (unsigned int) c.x[6], (unsigned int) c.x[7]));
83901 DUK__FAILED("invalid result from 1.0 + 0.5ulp");
83902 }
83903
83904 /* (1.0 + ulp) + 2^(-53): result is midway between 1.0 + ulp and 1.0 + 2*ulp.
83905 * Round to nearest: 1.0 + 2*ulp (round to even mantissa)
83906 * Round to +Inf: 1.0 + 2*ulp
83907 * Round to -Inf: 1.0 + ulp
83908 * Round to zero: 1.0 + ulp
83909 * => Correct result eliminates round to -Inf and round to zero.
83910 */
83911 DUK__DOUBLE_INIT(&a, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01);
83912 DUK__DOUBLE_INIT(&b, 0x3c, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
83913 DUK_MEMSET((void *) &c, 0, sizeof(c));
83914 c.d = a.d + b.d;
83915 if (!DUK__DOUBLE_COMPARE(&c, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02)) {
83916 DUK_D(DUK_DPRINT("broken result (native endiannesss): %02x %02x %02x %02x %02x %02x %02x %02x",
83917 (unsigned int) c.x[0], (unsigned int) c.x[1],
83918 (unsigned int) c.x[2], (unsigned int) c.x[3],
83919 (unsigned int) c.x[4], (unsigned int) c.x[5],
83920 (unsigned int) c.x[6], (unsigned int) c.x[7]));
83921 DUK__FAILED("invalid result from (1.0 + ulp) + 0.5ulp");
83922 }
83923
83924 /* Could do negative number testing too, but the tests above should
83925 * differentiate between IEEE 754 rounding modes.
83926 */
83927 return error_count;
83928}
83929
83930/*
83931 * fmod(): often a portability issue in embedded or bare platform targets.
83932 * Check for at least minimally correct behavior. Unlike some other math
83933 * functions (like cos()) Duktape relies on fmod() internally too.
83934 */
83935
83936DUK_LOCAL duk_uint_t duk__selftest_fmod(void) {
83937 duk_uint_t error_count = 0;
83938 duk__test_double_union u1, u2;
83939
83940 /* fmod() with integer argument and exponent 2^32 is used by e.g.
83941 * ToUint32() and some Duktape internals.
83942 */
83943 u1.d = DUK_FMOD(10.0, 4294967296.0);
83944 u2.d = 10.0;
83945 DUK__DBLUNION_CMP_TRUE(&u1, &u2);
83946
83947 u1.d = DUK_FMOD(4294967306.0, 4294967296.0);
83948 u2.d = 10.0;
83949 DUK__DBLUNION_CMP_TRUE(&u1, &u2);
83950
83951 u1.d = DUK_FMOD(73014444042.0, 4294967296.0);
83952 u2.d = 10.0;
83953 DUK__DBLUNION_CMP_TRUE(&u1, &u2);
83954
83955 /* C99 behavior is for fmod() result sign to mathc argument sign. */
83956 u1.d = DUK_FMOD(-10.0, 4294967296.0);
83957 u2.d = -10.0;
83958 DUK__DBLUNION_CMP_TRUE(&u1, &u2);
83959
83960 u1.d = DUK_FMOD(-4294967306.0, 4294967296.0);
83961 u2.d = -10.0;
83962 DUK__DBLUNION_CMP_TRUE(&u1, &u2);
83963
83964 u1.d = DUK_FMOD(-73014444042.0, 4294967296.0);
83965 u2.d = -10.0;
83966 DUK__DBLUNION_CMP_TRUE(&u1, &u2);
83967
83968 return error_count;
83969}
83970
83971/*
83972 * Struct size/alignment if platform requires it
83973 *
83974 * There are some compiler specific struct padding pragmas etc in use, this
83975 * selftest ensures they're correctly detected and used.
83976 */
83977
83978DUK_LOCAL duk_uint_t duk__selftest_struct_align(void) {
83979 duk_uint_t error_count = 0;
83980
83981#if (DUK_USE_ALIGN_BY == 4)
83982 if ((sizeof(duk_hbuffer_fixed) % 4) != 0) {
83983 DUK__FAILED("sizeof(duk_hbuffer_fixed) not aligned to 4");
83984 }
83985#elif (DUK_USE_ALIGN_BY == 8)
83986 if ((sizeof(duk_hbuffer_fixed) % 8) != 0) {
83987 DUK__FAILED("sizeof(duk_hbuffer_fixed) not aligned to 8");
83988 }
83989#elif (DUK_USE_ALIGN_BY == 1)
83990 /* no check */
83991#else
83992#error invalid DUK_USE_ALIGN_BY
83993#endif
83994 return error_count;
83995}
83996
83997/*
83998 * 64-bit arithmetic
83999 *
84000 * There are some platforms/compilers where 64-bit types are available
84001 * but don't work correctly. Test for known cases.
84002 */
84003
84004DUK_LOCAL duk_uint_t duk__selftest_64bit_arithmetic(void) {
84005 duk_uint_t error_count = 0;
84006#if defined(DUK_USE_64BIT_OPS)
84007 volatile duk_int64_t i;
84008 volatile duk_double_t d;
84009
84010 /* Catch a double-to-int64 cast issue encountered in practice. */
84011 d = 2147483648.0;
84012 i = (duk_int64_t) d;
84013 if (i != 0x80000000LL) {
84014 DUK__FAILED("casting 2147483648.0 to duk_int64_t failed");
84015 }
84016#else
84017 /* nop */
84018#endif
84019 return error_count;
84020}
84021
84022/*
84023 * Casting
84024 */
84025
84026DUK_LOCAL duk_uint_t duk__selftest_cast_double_to_small_uint(void) {
84027 /*
84028 * https://github.com/svaarala/duktape/issues/127#issuecomment-77863473
84029 */
84030
84031 duk_uint_t error_count = 0;
84032
84033 duk_double_t d1, d2;
84034 duk_small_uint_t u;
84035
84036 duk_double_t d1v, d2v;
84037 duk_small_uint_t uv;
84038
84039 /* Test without volatiles */
84040
84041 d1 = 1.0;
84042 u = (duk_small_uint_t) d1;
84043 d2 = (duk_double_t) u;
84044
84045 if (!(d1 == 1.0 && u == 1 && d2 == 1.0 && d1 == d2)) {
84046 DUK__FAILED("double to duk_small_uint_t cast failed");
84047 }
84048
84049 /* Same test with volatiles */
84050
84051 d1v = 1.0;
84052 uv = (duk_small_uint_t) d1v;
84053 d2v = (duk_double_t) uv;
84054
84055 if (!(d1v == 1.0 && uv == 1 && d2v == 1.0 && d1v == d2v)) {
84056 DUK__FAILED("double to duk_small_uint_t cast failed");
84057 }
84058
84059 return error_count;
84060}
84061
84062DUK_LOCAL duk_uint_t duk__selftest_cast_double_to_uint32(void) {
84063 /*
84064 * This test fails on an exotic ARM target; double-to-uint
84065 * cast is incorrectly clamped to -signed- int highest value.
84066 *
84067 * https://github.com/svaarala/duktape/issues/336
84068 */
84069
84070 duk_uint_t error_count = 0;
84071 duk_double_t dv;
84072 duk_uint32_t uv;
84073
84074 dv = 3735928559.0; /* 0xdeadbeef in decimal */
84075 uv = (duk_uint32_t) dv;
84076
84077 if (uv != 0xdeadbeefUL) {
84078 DUK__FAILED("double to duk_uint32_t cast failed");
84079 }
84080
84081 return error_count;
84082}
84083
84084/*
84085 * Minimal test of user supplied allocation functions
84086 *
84087 * - Basic alloc + realloc + free cycle
84088 *
84089 * - Realloc to significantly larger size to (hopefully) trigger a
84090 * relocation and check that relocation copying works
84091 */
84092
84093DUK_LOCAL duk_uint_t duk__selftest_alloc_funcs(duk_alloc_function alloc_func,
84094 duk_realloc_function realloc_func,
84095 duk_free_function free_func,
84096 void *udata) {
84097 duk_uint_t error_count = 0;
84098 void *ptr;
84099 void *new_ptr;
84100 duk_small_int_t i, j;
84101 unsigned char x;
84102
84103 if (alloc_func == NULL || realloc_func == NULL || free_func == NULL) {
84104 return 0;
84105 }
84106
84107 for (i = 1; i <= 256; i++) {
84108 ptr = alloc_func(udata, i);
84109 if (ptr == NULL) {
84110 DUK_D(DUK_DPRINT("alloc failed, ignore"));
84111 continue; /* alloc failed, ignore */
84112 }
84113 for (j = 0; j < i; j++) {
84114 ((unsigned char *) ptr)[j] = (unsigned char) (0x80 + j);
84115 }
84116 new_ptr = realloc_func(udata, ptr, 1024);
84117 if (new_ptr == NULL) {
84118 DUK_D(DUK_DPRINT("realloc failed, ignore"));
84119 free_func(udata, ptr);
84120 continue; /* realloc failed, ignore */
84121 }
84122 ptr = new_ptr;
84123 for (j = 0; j < i; j++) {
84124 x = ((unsigned char *) ptr)[j];
84125 if (x != (unsigned char) (0x80 + j)) {
84126 DUK_D(DUK_DPRINT("byte at index %ld doesn't match after realloc: %02lx",
84127 (long) j, (unsigned long) x));
84128 DUK__FAILED("byte compare after realloc");
84129 break;
84130 }
84131 }
84132 free_func(udata, ptr);
84133 }
84134
84135 return error_count;
84136}
84137
84138/*
84139 * Self test main
84140 */
84141
84142DUK_INTERNAL duk_uint_t duk_selftest_run_tests(duk_alloc_function alloc_func,
84143 duk_realloc_function realloc_func,
84144 duk_free_function free_func,
84145 void *udata) {
84146 duk_uint_t error_count = 0;
84147
84148 DUK_D(DUK_DPRINT("self test starting"));
84149
84150 error_count += duk__selftest_types();
84151 error_count += duk__selftest_packed_tval();
84152 error_count += duk__selftest_twos_complement();
84153 error_count += duk__selftest_byte_order();
84154 error_count += duk__selftest_bswap_macros();
84155 error_count += duk__selftest_double_union_size();
84156 error_count += duk__selftest_double_aliasing();
84157 error_count += duk__selftest_double_zero_sign();
84158 error_count += duk__selftest_double_rounding();
84159 error_count += duk__selftest_fmod();
84160 error_count += duk__selftest_struct_align();
84161 error_count += duk__selftest_64bit_arithmetic();
84162 error_count += duk__selftest_cast_double_to_small_uint();
84163 error_count += duk__selftest_cast_double_to_uint32();
84164 error_count += duk__selftest_alloc_funcs(alloc_func, realloc_func, free_func, udata);
84165
84166 DUK_D(DUK_DPRINT("self test complete, total error count: %ld", (long) error_count));
84167
84168 return error_count;
84169}
84170
84171#endif /* DUK_USE_SELF_TESTS */
84172
84173/* automatic undefs */
84174#undef DUK__DBLUNION_CMP_FALSE
84175#undef DUK__DBLUNION_CMP_TRUE
84176#undef DUK__DOUBLE_COMPARE
84177#undef DUK__DOUBLE_INIT
84178#undef DUK__FAILED
84179#undef DUK__U32_INIT
84180/* #include duk_internal.h -> already included */
84181
84182#if defined(DUK_USE_FASTINT)
84183
84184/*
84185 * Manually optimized double-to-fastint downgrade check.
84186 *
84187 * This check has a large impact on performance, especially for fastint
84188 * slow paths, so must be changed carefully. The code should probably be
84189 * optimized for the case where the result does not fit into a fastint,
84190 * to minimize the penalty for "slow path code" dealing with fractions etc.
84191 *
84192 * At least on one tested soft float ARM platform double-to-int64 coercion
84193 * is very slow (and sometimes produces incorrect results, see self tests).
84194 * This algorithm combines a fastint compatibility check and extracting the
84195 * integer value from an IEEE double for setting the tagged fastint. For
84196 * other platforms a more naive approach might be better.
84197 *
84198 * See doc/fastint.rst for details.
84199 */
84200
84201DUK_INTERNAL DUK_ALWAYS_INLINE void duk_tval_set_number_chkfast_fast(duk_tval *tv, duk_double_t x) {
84203 duk_int64_t i;
84204 duk_small_int_t expt;
84205 duk_small_int_t shift;
84206
84207 /* XXX: optimize for packed duk_tval directly? */
84208
84209 du.d = x;
84210 i = (duk_int64_t) DUK_DBLUNION_GET_INT64(&du);
84211 expt = (duk_small_int_t) ((i >> 52) & 0x07ff);
84212 shift = expt - 1023;
84213
84214 if (shift >= 0 && shift <= 46) { /* exponents 1023 to 1069 */
84215 duk_int64_t t;
84216
84217 if (((0x000fffffffffffffLL >> shift) & i) == 0) {
84218 t = i | 0x0010000000000000LL; /* implicit leading one */
84219 t = t & 0x001fffffffffffffLL;
84220 t = t >> (52 - shift);
84221 if (i < 0) {
84222 t = -t;
84223 }
84224 DUK_TVAL_SET_FASTINT(tv, t);
84225 return;
84226 }
84227 } else if (shift == -1023) { /* exponent 0 */
84228 if (i >= 0 && (i & 0x000fffffffffffffLL) == 0) {
84229 /* Note: reject negative zero. */
84230 DUK_TVAL_SET_FASTINT(tv, (duk_int64_t) 0);
84231 return;
84232 }
84233 } else if (shift == 47) { /* exponent 1070 */
84234 if (i < 0 && (i & 0x000fffffffffffffLL) == 0) {
84235 DUK_TVAL_SET_FASTINT(tv, (duk_int64_t) DUK_FASTINT_MIN);
84236 return;
84237 }
84238 }
84239
84240 DUK_TVAL_SET_DOUBLE(tv, x);
84241 return;
84242}
84243
84244DUK_INTERNAL DUK_NOINLINE void duk_tval_set_number_chkfast_slow(duk_tval *tv, duk_double_t x) {
84245 duk_tval_set_number_chkfast_fast(tv, x);
84246}
84247
84248/*
84249 * Manually optimized number-to-double conversion
84250 */
84251
84252#if defined(DUK_USE_FASTINT) && defined(DUK_USE_PACKED_TVAL)
84253DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_packed(duk_tval *tv) {
84255 duk_uint64_t t;
84256
84257 t = (duk_uint64_t) DUK_DBLUNION_GET_UINT64(tv);
84258 if ((t >> 48) != DUK_TAG_FASTINT) {
84259 return tv->d;
84260 } else if (t & 0x0000800000000000ULL) {
84261 t = (duk_uint64_t) (-((duk_int64_t) t)); /* avoid unary minus on unsigned */
84262 t = t & 0x0000ffffffffffffULL; /* negative */
84263 t |= 0xc330000000000000ULL;
84264 DUK_DBLUNION_SET_UINT64(&du, t);
84265 return du.d + 4503599627370496.0; /* 1 << 52 */
84266 } else if (t != 0) {
84267 t &= 0x0000ffffffffffffULL; /* positive */
84268 t |= 0x4330000000000000ULL;
84269 DUK_DBLUNION_SET_UINT64(&du, t);
84270 return du.d - 4503599627370496.0; /* 1 << 52 */
84271 } else {
84272 return 0.0; /* zero */
84273 }
84274}
84275#endif /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */
84276
84277#if 0 /* unused */
84278#if defined(DUK_USE_FASTINT) && !defined(DUK_USE_PACKED_TVAL)
84279DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_unpacked(duk_tval *tv) {
84281 duk_uint64_t t;
84282
84283 DUK_ASSERT(tv->t == DUK_TAG_NUMBER || tv->t == DUK_TAG_FASTINT);
84284
84285 if (tv->t == DUK_TAG_FASTINT) {
84286 if (tv->v.fi >= 0) {
84287 t = 0x4330000000000000ULL | (duk_uint64_t) tv->v.fi;
84288 DUK_DBLUNION_SET_UINT64(&du, t);
84289 return du.d - 4503599627370496.0; /* 1 << 52 */
84290 } else {
84291 t = 0xc330000000000000ULL | (duk_uint64_t) (-tv->v.fi);
84292 DUK_DBLUNION_SET_UINT64(&du, t);
84293 return du.d + 4503599627370496.0; /* 1 << 52 */
84294 }
84295 } else {
84296 return tv->v.d;
84297 }
84298}
84299#endif /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */
84300#endif /* 0 */
84301
84302#if defined(DUK_USE_FASTINT) && !defined(DUK_USE_PACKED_TVAL)
84303DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_tval_get_number_unpacked_fastint(duk_tval *tv) {
84305 duk_uint64_t t;
84306
84307 DUK_ASSERT(tv->t == DUK_TAG_FASTINT);
84308
84309 if (tv->v.fi >= 0) {
84310 t = 0x4330000000000000ULL | (duk_uint64_t) tv->v.fi;
84311 DUK_DBLUNION_SET_UINT64(&du, t);
84312 return du.d - 4503599627370496.0; /* 1 << 52 */
84313 } else {
84314 t = 0xc330000000000000ULL | (duk_uint64_t) (-tv->v.fi);
84315 DUK_DBLUNION_SET_UINT64(&du, t);
84316 return du.d + 4503599627370496.0; /* 1 << 52 */
84317 }
84318}
84319#endif /* DUK_USE_FASTINT && DUK_USE_PACKED_TVAL */
84320
84321#endif /* DUK_USE_FASTINT */
84322/*
84323 * Unicode support tables automatically generated during build.
84324 */
84325
84326/* #include duk_internal.h -> already included */
84327
84328/*
84329 * Unicode tables containing ranges of Unicode characters in a
84330 * packed format. These tables are used to match non-ASCII
84331 * characters of complex productions by resorting to a linear
84332 * range-by-range comparison. This is very slow, but is expected
84333 * to be very rare in practical Ecmascript source code, and thus
84334 * compactness is most important.
84335 *
84336 * The tables are matched using uni_range_match() and the format
84337 * is described in tools/extract_chars.py.
84338 */
84339
84340#if defined(DUK_USE_SOURCE_NONBMP)
84341/* IdentifierStart production with ASCII excluded */
84342/* duk_unicode_ids_noa[] */
84343/*
84344 * Automatically generated by extract_chars.py, do not edit!
84345 */
84346
84347const duk_uint8_t duk_unicode_ids_noa[1036] = {
84348249,176,176,80,111,7,47,15,47,254,11,197,191,0,72,2,15,115,66,19,50,7,2,34,
843492,240,66,244,50,247,185,249,98,241,99,8,241,127,58,240,182,47,31,241,191,
8435021,18,245,50,15,1,24,27,35,15,2,2,240,239,15,244,156,15,10,241,26,21,6,240,
84351101,10,4,15,9,240,159,57,240,82,127,56,242,100,15,4,8,159,1,240,5,115,19,
84352240,98,98,4,52,15,2,14,18,47,0,31,5,85,19,240,98,98,18,18,31,17,50,15,5,47,
843532,130,34,240,98,98,18,68,15,4,15,1,31,9,12,115,19,240,98,98,18,68,15,16,18,
8435447,1,15,3,2,84,34,52,18,2,20,20,36,191,8,15,38,114,34,240,114,240,4,15,12,
8435538,31,16,5,114,34,240,114,146,68,15,18,2,31,1,31,4,114,34,241,147,15,2,6,
8435641,47,10,86,240,36,240,130,130,3,111,44,242,2,29,111,44,18,3,18,3,7,50,98,
8435734,2,3,18,50,26,3,66,15,7,63,18,15,49,114,241,79,13,79,101,241,191,6,15,2,
8435885,52,4,24,37,205,15,3,241,98,6,3,241,178,255,224,63,35,54,32,35,63,25,35,
8435963,17,35,54,32,35,62,47,41,35,63,51,241,127,0,240,47,70,53,79,254,21,227,
84360240,18,240,166,243,180,168,194,63,0,240,47,0,240,47,0,194,47,1,242,79,21,5,
8436115,53,244,137,67,241,34,6,243,107,240,255,35,240,227,76,241,197,240,175,40,
84362240,122,242,95,68,15,79,241,255,3,111,41,240,238,27,241,207,12,241,79,27,
8436343,241,67,143,82,50,52,26,251,15,50,255,224,8,53,63,22,53,55,32,32,32,47,
8436415,63,37,38,32,66,38,67,53,92,98,38,246,96,224,240,44,245,112,80,57,32,68,
84365112,32,32,35,42,51,100,80,240,63,25,255,233,107,241,242,241,242,247,87,52,
8436629,241,98,6,3,242,136,15,2,240,122,98,98,98,98,98,98,98,111,66,15,254,12,
84367146,240,184,132,52,95,70,114,47,74,35,111,25,79,78,240,63,11,242,127,0,255,
84368224,244,255,240,0,138,143,60,255,240,4,12,143,28,255,227,127,243,95,30,63,
84369253,79,0,177,240,111,31,240,47,15,63,64,241,152,63,87,63,20,39,243,26,34,
8437035,47,7,240,255,36,240,15,34,243,5,64,32,223,12,191,7,240,191,13,143,31,
84371240,224,240,36,41,180,47,25,240,146,39,240,111,7,64,79,34,32,65,52,48,32,
84372240,162,58,130,213,53,53,166,38,47,27,41,191,99,240,255,255,0,26,150,223,7,
8437395,33,255,240,0,255,143,254,6,3,245,175,24,109,70,2,146,194,66,2,18,18,245,
84374207,19,255,224,93,240,79,48,63,38,241,171,246,100,47,119,241,111,10,127,10,
84375207,73,69,53,53,50,241,91,47,10,47,3,33,46,61,241,79,107,243,127,37,255,
84376223,13,79,33,242,31,16,240,47,11,111,22,191,14,63,20,87,36,241,207,142,240,
8437779,20,95,20,95,24,159,36,248,239,254,2,154,240,107,127,138,83,2,241,194,20,
843783,240,123,240,122,240,255,51,240,50,27,240,107,240,175,56,242,135,31,50,15,
843791,50,34,240,191,30,240,212,240,223,21,114,240,207,13,242,107,240,107,240,
8438062,240,47,96,243,159,41,242,62,242,63,254,32,79,37,243,223,29,241,47,9,240,
84381207,20,241,191,19,64,223,32,240,3,240,112,32,241,95,2,47,9,244,102,32,35,
8438246,41,143,31,241,135,49,63,6,38,33,36,64,240,64,212,249,15,37,240,67,242,
84383127,32,240,97,32,250,175,31,241,179,241,111,32,240,96,242,223,27,244,127,
8438410,255,224,122,243,15,17,15,254,11,79,41,255,152,47,21,240,48,242,63,14,
84385255,226,100,255,226,140,245,143,95,240,63,180,255,233,176,255,227,33,255,
84386238,197,255,225,57,255,240,1,10,223,254,18,184,240,255,99,240,239,4,242,15,
843872,63,17,240,86,240,63,254,38,79,53,192,243,76,243,32,241,31,255,0,6,223,
84388240,95,254,30,95,255,0,20,1,31,254,175,47,91,108,72,137,255,240,0,101,175,
8438969,47,55,33,48,49,51,43,32,38,47,49,35,55,38,47,12,35,36,32,70,47,254,4,99,
84390240,146,240,146,240,242,240,146,240,242,240,146,240,242,240,146,240,242,
84391240,146,127,254,242,143,181,242,223,52,255,227,176,50,240,178,18,3,2,146,
8439250,2,7,5,2,2,2,34,18,3,2,2,2,2,2,18,3,50,98,50,50,2,146,240,22,34,66,240,
8439331,255,0,0,56,255,240,9,92,159,27,255,239,39,207,206,63,255,0,5,116,255,
84394240,1,133,47,254,17,0,
84395};
84396#else
84397/* IdentifierStart production with ASCII and non-BMP excluded */
84398/* duk_unicode_ids_noabmp[] */
84399/*
84400 * Automatically generated by extract_chars.py, do not edit!
84401 */
84402
84403const duk_uint8_t duk_unicode_ids_noabmp[625] = {
84404249,176,176,80,111,7,47,15,47,254,11,197,191,0,72,2,15,115,66,19,50,7,2,34,
844052,240,66,244,50,247,185,249,98,241,99,8,241,127,58,240,182,47,31,241,191,
8440621,18,245,50,15,1,24,27,35,15,2,2,240,239,15,244,156,15,10,241,26,21,6,240,
84407101,10,4,15,9,240,159,57,240,82,127,56,242,100,15,4,8,159,1,240,5,115,19,
84408240,98,98,4,52,15,2,14,18,47,0,31,5,85,19,240,98,98,18,18,31,17,50,15,5,47,
844092,130,34,240,98,98,18,68,15,4,15,1,31,9,12,115,19,240,98,98,18,68,15,16,18,
8441047,1,15,3,2,84,34,52,18,2,20,20,36,191,8,15,38,114,34,240,114,240,4,15,12,
8441138,31,16,5,114,34,240,114,146,68,15,18,2,31,1,31,4,114,34,241,147,15,2,6,
8441241,47,10,86,240,36,240,130,130,3,111,44,242,2,29,111,44,18,3,18,3,7,50,98,
8441334,2,3,18,50,26,3,66,15,7,63,18,15,49,114,241,79,13,79,101,241,191,6,15,2,
8441485,52,4,24,37,205,15,3,241,98,6,3,241,178,255,224,63,35,54,32,35,63,25,35,
8441563,17,35,54,32,35,62,47,41,35,63,51,241,127,0,240,47,70,53,79,254,21,227,
84416240,18,240,166,243,180,168,194,63,0,240,47,0,240,47,0,194,47,1,242,79,21,5,
8441715,53,244,137,67,241,34,6,243,107,240,255,35,240,227,76,241,197,240,175,40,
84418240,122,242,95,68,15,79,241,255,3,111,41,240,238,27,241,207,12,241,79,27,
8441943,241,67,143,82,50,52,26,251,15,50,255,224,8,53,63,22,53,55,32,32,32,47,
8442015,63,37,38,32,66,38,67,53,92,98,38,246,96,224,240,44,245,112,80,57,32,68,
84421112,32,32,35,42,51,100,80,240,63,25,255,233,107,241,242,241,242,247,87,52,
8442229,241,98,6,3,242,136,15,2,240,122,98,98,98,98,98,98,98,111,66,15,254,12,
84423146,240,184,132,52,95,70,114,47,74,35,111,25,79,78,240,63,11,242,127,0,255,
84424224,244,255,240,0,138,143,60,255,240,4,12,143,28,255,227,127,243,95,30,63,
84425253,79,0,177,240,111,31,240,47,15,63,64,241,152,63,87,63,20,39,243,26,34,
8442635,47,7,240,255,36,240,15,34,243,5,64,32,223,12,191,7,240,191,13,143,31,
84427240,224,240,36,41,180,47,25,240,146,39,240,111,7,64,79,34,32,65,52,48,32,
84428240,162,58,130,213,53,53,166,38,47,27,41,191,99,240,255,255,0,26,150,223,7,
8442995,33,255,240,0,255,143,254,6,3,245,175,24,109,70,2,146,194,66,2,18,18,245,
84430207,19,255,224,93,240,79,48,63,38,241,171,246,100,47,119,241,111,10,127,10,
84431207,73,69,53,53,50,0,
84432};
84433#endif
84434
84435#if defined(DUK_USE_SOURCE_NONBMP)
84436/* IdentifierStart production with Letter and ASCII excluded */
84437/* duk_unicode_ids_m_let_noa[] */
84438/*
84439 * Automatically generated by extract_chars.py, do not edit!
84440 */
84441
84442const duk_uint8_t duk_unicode_ids_m_let_noa[42] = {
84443255,240,0,94,18,255,233,99,241,51,63,254,215,32,240,184,240,2,255,240,6,89,
84444249,255,240,4,148,79,37,255,224,192,9,15,120,79,255,0,15,30,245,240,
84445};
84446#else
84447/* IdentifierStart production with Letter, ASCII, and non-BMP excluded */
84448/* duk_unicode_ids_m_let_noabmp[] */
84449/*
84450 * Automatically generated by extract_chars.py, do not edit!
84451 */
84452
84453const duk_uint8_t duk_unicode_ids_m_let_noabmp[24] = {
84454255,240,0,94,18,255,233,99,241,51,63,254,215,32,240,184,240,2,255,240,6,89,
84455249,0,
84456};
84457#endif
84458
84459#if defined(DUK_USE_SOURCE_NONBMP)
84460/* IdentifierPart production with IdentifierStart and ASCII excluded */
84461/* duk_unicode_idp_m_ids_noa[] */
84462/*
84463 * Automatically generated by extract_chars.py, do not edit!
84464 */
84465
84466const duk_uint8_t duk_unicode_idp_m_ids_noa[530] = {
84467255,225,243,246,15,254,0,116,255,191,29,32,33,33,32,243,170,242,47,15,112,
84468245,118,53,49,35,57,240,144,241,15,11,244,218,240,25,241,56,241,67,40,34,
8446936,241,210,246,173,47,17,242,130,47,2,38,177,57,240,50,242,160,38,49,50,
84470160,177,57,240,50,242,160,36,81,50,64,240,107,64,194,242,160,39,34,34,240,
8447197,57,240,50,242,160,38,49,50,145,177,57,240,64,242,212,66,35,160,240,9,
84472240,35,242,198,34,35,129,193,57,240,50,242,160,38,34,35,129,193,57,240,50,
84473242,198,34,35,160,177,57,240,65,243,128,85,32,39,121,49,242,240,54,215,41,
84474244,144,53,33,197,57,243,1,121,192,32,32,81,242,63,4,33,106,47,20,160,245,
84475111,4,41,211,82,34,54,67,235,46,255,225,179,47,254,42,98,240,242,240,241,
84476241,1,243,47,16,160,57,241,50,57,245,209,241,64,246,139,91,185,247,41,242,
84477244,242,185,47,13,58,121,240,141,243,68,242,31,1,201,240,56,210,241,12,57,
84478241,237,242,47,4,153,121,246,130,47,5,80,82,65,251,143,38,100,255,225,0,31,
8447935,31,5,15,109,197,4,191,254,175,34,247,240,245,47,16,255,225,30,95,91,31,
84480255,0,100,121,159,55,5,159,18,31,66,31,254,0,64,64,80,240,148,244,161,242,
8448179,2,185,127,2,240,9,240,231,240,188,241,227,242,29,240,25,192,185,242,29,
84482208,145,57,241,50,242,64,34,49,97,32,241,180,97,253,231,33,57,255,240,3,
84483225,128,255,225,213,240,15,2,240,4,31,10,47,178,159,23,15,254,27,16,253,64,
84484248,116,255,224,25,159,254,68,178,33,99,241,162,80,249,113,255,228,13,47,
8448539,239,17,159,1,63,31,175,39,151,47,22,210,159,37,13,47,34,218,36,159,68,
84486183,15,146,182,151,63,42,2,99,19,42,11,19,100,79,178,240,42,159,72,240,77,
84487159,199,99,143,13,31,68,240,31,1,159,67,201,159,69,229,159,254,9,169,255,
84488226,57,114,127,2,159,42,240,98,223,255,0,60,157,159,120,79,45,111,11,159,
84489254,46,191,30,240,35,255,240,3,191,225,255,240,0,59,164,69,151,54,241,3,
84490248,98,255,228,125,242,47,254,15,79,39,95,34,144,240,0,240,132,46,255,228,
8449168,98,240,19,98,18,79,254,121,150,245,246,105,255,240,192,105,175,224,0,
84492};
84493#else
84494/* IdentifierPart production with IdentifierStart, ASCII, and non-BMP excluded */
84495/* duk_unicode_idp_m_ids_noabmp[] */
84496/*
84497 * Automatically generated by extract_chars.py, do not edit!
84498 */
84499
84500const duk_uint8_t duk_unicode_idp_m_ids_noabmp[357] = {
84501255,225,243,246,15,254,0,116,255,191,29,32,33,33,32,243,170,242,47,15,112,
84502245,118,53,49,35,57,240,144,241,15,11,244,218,240,25,241,56,241,67,40,34,
8450336,241,210,246,173,47,17,242,130,47,2,38,177,57,240,50,242,160,38,49,50,
84504160,177,57,240,50,242,160,36,81,50,64,240,107,64,194,242,160,39,34,34,240,
8450597,57,240,50,242,160,38,49,50,145,177,57,240,64,242,212,66,35,160,240,9,
84506240,35,242,198,34,35,129,193,57,240,50,242,160,38,34,35,129,193,57,240,50,
84507242,198,34,35,160,177,57,240,65,243,128,85,32,39,121,49,242,240,54,215,41,
84508244,144,53,33,197,57,243,1,121,192,32,32,81,242,63,4,33,106,47,20,160,245,
84509111,4,41,211,82,34,54,67,235,46,255,225,179,47,254,42,98,240,242,240,241,
84510241,1,243,47,16,160,57,241,50,57,245,209,241,64,246,139,91,185,247,41,242,
84511244,242,185,47,13,58,121,240,141,243,68,242,31,1,201,240,56,210,241,12,57,
84512241,237,242,47,4,153,121,246,130,47,5,80,82,65,251,143,38,100,255,225,0,31,
8451335,31,5,15,109,197,4,191,254,175,34,247,240,245,47,16,255,225,30,95,91,31,
84514255,0,100,121,159,55,5,159,18,31,66,31,254,0,64,64,80,240,148,244,161,242,
8451579,2,185,127,2,240,9,240,231,240,188,241,227,242,29,240,25,192,185,242,29,
84516208,145,57,241,50,242,64,34,49,97,32,241,180,97,253,231,33,57,255,240,3,
84517225,128,255,225,213,240,15,2,240,4,31,10,47,178,159,23,0,
84518};
84519#endif
84520
84521/*
84522 * Case conversion tables generated using tools/extract_caseconv.py.
84523 */
84524
84525/* duk_unicode_caseconv_uc[] */
84526/* duk_unicode_caseconv_lc[] */
84527
84528/*
84529 * Automatically generated by extract_caseconv.py, do not edit!
84530 */
84531
84532const duk_uint8_t duk_unicode_caseconv_uc[1386] = {
84533144,3,128,3,0,184,7,192,6,192,112,35,242,199,224,64,74,192,49,32,128,162,
84534128,108,65,1,189,129,254,131,3,173,3,136,6,7,98,7,34,68,15,12,14,140,72,30,
84535104,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,
8453633,4,62,0,62,16,32,124,64,124,96,48,249,0,249,64,129,243,1,243,129,3,232,3,
84537233,1,135,216,7,218,4,15,184,15,221,2,31,114,31,200,8,62,236,63,180,8,125,
84538224,127,224,16,251,208,255,80,33,247,193,255,160,67,246,3,247,0,135,244,7,
84539246,1,15,240,15,244,2,33,112,33,96,32,73,160,73,108,104,176,192,176,1,121,
84540104,0,133,2,106,183,1,58,10,31,232,63,228,38,162,1,1,1,0,48,2,102,2,100,12,
845414,232,4,228,64,10,88,10,81,112,23,160,23,144,96,48,96,48,64,128,104,64,104,
845421,128,218,0,217,130,1,206,1,205,16,3,190,3,188,36,7,228,7,224,160,17,24,17,
8454316,144,36,112,36,96,160,110,32,110,0,128,246,64,246,6,2,48,130,48,17,4,139,
845444,138,54,9,132,9,130,28,19,68,19,65,128,240,8,240,4,177,234,17,234,6,3,234,
8454535,235,33,11,26,11,25,193,150,64,150,64,50,44,236,44,235,5,76,131,76,128,
8454694,154,6,154,0,117,57,29,57,16,122,115,58,115,35,244,239,84,239,32,169,223,
84547233,223,130,211,200,211,200,2,167,151,167,150,21,79,107,79,104,8,112,26,
84548208,26,192,64,56,160,56,128,192,113,128,113,1,128,249,0,248,130,2,128,1,
84549166,4,7,240,7,238,8,177,204,177,200,16,96,49,0,48,224,128,110,64,110,1,1,
8455051,83,213,2,0,48,35,192,35,176,64,77,32,50,192,139,73,196,49,193,127,48,2,
84551212,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,
845526,100,6,96,6,104,8,244,6,120,8,128,6,160,6,156,6,252,7,220,7,116,6,56,7,
84553204,7,196,9,64,177,188,9,68,177,180,9,72,177,192,9,76,6,4,9,80,6,24,9,100,
845546,60,9,108,6,64,9,114,158,172,9,128,6,76,9,134,158,176,9,140,6,80,9,150,
84555158,52,9,160,6,92,9,172,177,136,9,178,158,180,9,196,177,184,9,200,6,116,9,
84556212,6,124,9,244,177,144,10,30,158,196,10,32,6,184,10,36,9,16,10,48,9,20,10,
8455772,6,220,10,118,158,200,10,122,158,192,13,20,14,100,13,220,13,216,14,176,
8455814,24,15,8,14,140,15,48,14,48,15,64,14,72,15,68,14,96,15,84,14,152,15,88,
8455914,128,15,92,15,60,15,192,14,104,15,196,14,132,15,200,15,228,15,204,13,252,
8456015,212,14,84,19,60,19,0,114,0,16,72,114,4,16,80,114,8,16,120,114,20,16,136,
84561114,24,16,168,114,28,17,136,114,34,153,40,117,230,157,244,117,244,177,140,
84562122,108,121,128,126,248,14,100,127,148,127,176,133,56,132,200,134,16,134,
8456312,177,132,177,128,177,148,8,232,177,152,8,248,179,204,179,202,158,50,158,
8456446,173,78,158,207,48,6,252,0,166,0,166,2,147,1,94,0,39,0,248,64,9,64,97,
84565128,114,24,28,200,24,64,24,8,29,134,7,74,6,16,6,2,11,15,2,154,130,169,15,
8456675,64,9,0,102,35,210,240,2,160,24,64,244,196,0,174,6,20,61,51,0,44,129,133,
8456715,77,64,8,32,87,195,234,16,29,40,24,152,250,150,7,74,6,38,6,0,62,169,129,
84568210,129,137,129,128,143,171,96,116,160,98,96,104,67,240,16,248,64,28,200,
84569252,12,62,18,7,50,63,5,15,133,1,204,143,193,195,225,96,115,35,240,144,248,
8457096,28,200,252,44,62,26,7,50,63,13,15,135,1,204,143,195,195,225,224,115,35,
84571241,16,248,64,28,200,252,76,62,18,7,50,63,21,15,133,1,204,143,197,195,225,
8457296,115,35,241,144,248,96,28,200,252,108,62,26,7,50,63,29,15,135,1,204,143,
84573199,195,225,224,115,35,242,16,249,64,28,200,252,140,62,82,7,50,63,37,15,
84574149,1,204,143,201,195,229,96,115,35,242,144,249,96,28,200,252,172,62,90,7,
8457550,63,45,15,151,1,204,143,203,195,229,224,115,35,243,16,249,64,28,200,252,
84576204,62,82,7,50,63,53,15,149,1,204,143,205,195,229,96,115,35,243,144,249,96,
8457728,200,252,236,62,90,7,50,63,61,15,151,1,204,143,207,195,229,224,115,35,
84578244,16,251,64,28,200,253,12,62,210,7,50,63,69,15,181,1,204,143,209,195,237,
8457996,115,35,244,144,251,96,28,200,253,44,62,218,7,50,63,77,15,183,1,204,143,
84580211,195,237,224,115,35,245,16,251,64,28,200,253,76,62,210,7,50,63,85,15,
84581181,1,204,143,213,195,237,96,115,35,245,144,251,96,28,200,253,108,62,218,7,
8458250,63,93,15,183,1,204,143,215,195,237,224,115,35,246,80,253,208,28,200,253,
84583156,7,34,7,50,63,105,1,195,1,204,143,219,64,114,32,104,67,246,248,28,136,
8458426,16,28,200,253,228,7,34,7,50,63,133,15,229,1,204,143,225,192,114,224,115,
8458535,248,144,28,72,28,200,254,52,7,46,6,132,63,143,129,203,129,161,1,204,143,
84586230,64,114,224,115,35,250,88,28,200,24,64,24,0,254,158,7,50,6,16,6,2,63,
84587173,1,204,129,161,15,235,224,115,32,97,0,104,67,252,88,29,40,24,64,24,0,
84588255,30,7,74,6,16,6,2,63,201,1,208,129,137,143,243,64,116,160,104,67,252,
84589248,29,40,24,64,26,16,255,148,63,244,7,50,63,231,1,212,129,204,143,250,64,
84590113,224,115,35,254,208,29,72,26,16,255,190,7,82,6,132,7,50,63,249,1,212,
84591129,204,253,128,64,8,192,8,223,96,48,2,48,2,79,216,20,0,140,0,153,246,7,
84592128,35,0,35,0,36,253,130,96,8,192,8,192,9,159,96,176,2,152,2,167,216,52,0,
84593166,0,169,246,39,2,162,2,163,125,138,64,168,128,166,191,98,176,42,32,41,
84594223,216,180,10,156,10,141,246,47,2,162,2,158,128,
84595};
84596const duk_uint8_t duk_unicode_caseconv_lc[680] = {
84597152,3,0,3,128,184,6,192,7,192,112,24,144,37,96,64,54,32,81,64,128,226,0,
84598235,65,129,199,1,230,130,3,145,3,177,34,7,70,7,134,36,15,244,13,236,24,32,
845990,34,129,0,65,0,67,4,0,166,32,172,41,132,40,11,64,19,9,208,85,184,80,19,
84600240,19,248,12,62,16,62,0,32,124,96,124,64,48,249,64,249,0,129,243,129,243,
846011,3,233,3,232,1,135,218,7,216,4,15,196,15,192,8,31,152,31,144,16,63,80,63,
8460264,32,126,224,126,192,16,253,208,251,128,33,252,129,247,32,131,251,3,250,0,
84603135,246,135,221,129,15,244,15,240,2,31,234,31,122,4,63,240,62,240,8,127,
84604232,125,240,17,11,1,11,129,2,75,98,77,3,69,128,5,134,11,203,31,128,143,193,
84605127,144,255,160,154,140,4,0,4,4,192,9,144,9,152,48,19,144,19,161,0,41,64,
8460641,101,192,94,64,94,129,128,193,0,193,130,1,160,1,161,6,3,102,3,104,8,7,44,
846077,48,72,14,240,14,248,144,31,32,31,48,64,63,0,63,37,0,136,128,136,196,129,
8460835,1,35,133,3,112,3,113,4,7,176,7,178,48,17,128,17,132,136,36,80,36,89,176,
8460976,16,76,32,224,154,0,154,44,7,128,7,128,101,143,80,15,80,176,31,89,31,81,
846108,88,206,88,208,12,178,0,178,5,145,103,89,103,96,42,100,10,100,18,244,208,
8461120,208,35,169,200,169,200,195,211,153,83,153,159,167,121,167,122,5,78,253,
8461278,254,22,158,66,158,68,21,60,181,60,184,170,123,74,123,80,67,0,211,1,64,2,
846131,172,1,173,4,3,136,3,140,12,7,20,7,24,16,31,184,31,192,34,199,34,199,48,
8461465,128,195,128,196,2,1,184,1,185,5,79,84,4,204,8,0,192,101,128,154,65,1,29,
84615129,30,2,16,199,45,39,5,251,240,23,128,15,240,24,16,37,48,24,96,37,64,24,
84616224,29,208,24,240,37,144,25,0,37,176,25,16,25,32,25,48,38,0,25,64,38,48,25,
84617112,38,128,25,128,25,144,25,208,39,32,25,240,39,80,26,112,26,128,26,224,40,
84618128,27,112,41,32,31,16,31,48,31,96,25,80,31,112,27,240,34,0,25,224,35,162,
84619198,80,35,208,25,160,35,226,198,96,36,48,24,0,36,64,40,144,36,80,40,192,55,
8462096,55,112,55,240,63,48,56,96,58,192,56,192,60,192,60,240,61,112,63,64,59,
84621128,63,144,63,32,76,0,76,241,233,224,13,241,251,193,251,49,252,193,252,49,
84622254,193,254,81,255,193,255,50,18,96,60,146,18,160,6,178,18,176,14,82,19,34,
8462320,226,24,50,24,66,198,2,198,18,198,32,38,178,198,49,215,210,198,64,39,210,
84624198,208,37,18,198,224,39,18,198,240,37,2,199,0,37,34,207,34,207,58,119,209,
84625215,154,120,186,120,202,120,208,38,90,122,176,37,202,122,192,38,26,122,208,
8462638,202,123,0,41,234,123,16,40,122,123,32,41,218,123,58,181,48,32,38,16,3,
8462772,24,56,
84628};
84629
84630#if defined(DUK_USE_REGEXP_CANON_WORKAROUND)
84631/*
84632 * Automatically generated by extract_caseconv.py, do not edit!
84633 */
84634
84635const duk_uint16_t duk_unicode_re_canon_lookup[65536] = {
846360,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,
8463728,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,
8463853,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,
8463978,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,65,66,67,68,69,70,
8464071,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,123,124,125,
84641126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
84642144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,
84643162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,
84644180,924,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,
84645198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,
84646216,217,218,219,220,221,222,223,192,193,194,195,196,197,198,199,200,201,
84647202,203,204,205,206,207,208,209,210,211,212,213,214,247,216,217,218,219,
84648220,221,222,376,256,256,258,258,260,260,262,262,264,264,266,266,268,268,
84649270,270,272,272,274,274,276,276,278,278,280,280,282,282,284,284,286,286,
84650288,288,290,290,292,292,294,294,296,296,298,298,300,300,302,302,304,305,
84651306,306,308,308,310,310,312,313,313,315,315,317,317,319,319,321,321,323,
84652323,325,325,327,327,329,330,330,332,332,334,334,336,336,338,338,340,340,
84653342,342,344,344,346,346,348,348,350,350,352,352,354,354,356,356,358,358,
84654360,360,362,362,364,364,366,366,368,368,370,370,372,372,374,374,376,377,
84655377,379,379,381,381,383,579,385,386,386,388,388,390,391,391,393,394,395,
84656395,397,398,399,400,401,401,403,404,502,406,407,408,408,573,411,412,413,
84657544,415,416,416,418,418,420,420,422,423,423,425,426,427,428,428,430,431,
84658431,433,434,435,435,437,437,439,440,440,442,443,444,444,446,503,448,449,
84659450,451,452,452,452,455,455,455,458,458,458,461,461,463,463,465,465,467,
84660467,469,469,471,471,473,473,475,475,398,478,478,480,480,482,482,484,484,
84661486,486,488,488,490,490,492,492,494,494,496,497,497,497,500,500,502,503,
84662504,504,506,506,508,508,510,510,512,512,514,514,516,516,518,518,520,520,
84663522,522,524,524,526,526,528,528,530,530,532,532,534,534,536,536,538,538,
84664540,540,542,542,544,545,546,546,548,548,550,550,552,552,554,554,556,556,
84665558,558,560,560,562,562,564,565,566,567,568,569,570,571,571,573,574,11390,
8466611391,577,577,579,580,581,582,582,584,584,586,586,588,588,590,590,11375,
8466711373,11376,385,390,597,393,394,600,399,602,400,42923L,605,606,607,403,
8466842924L,610,404,612,42893L,42922L,615,407,406,42926L,11362,42925L,621,622,
84669412,624,11374,413,627,628,415,630,631,632,633,634,635,636,11364,638,639,
84670422,641,642,425,644,645,646,42929L,430,580,433,434,581,653,654,655,656,657,
84671439,659,660,661,662,663,664,665,666,667,668,42930L,42928L,671,672,673,674,
84672675,676,677,678,679,680,681,682,683,684,685,686,687,688,689,690,691,692,
84673693,694,695,696,697,698,699,700,701,702,703,704,705,706,707,708,709,710,
84674711,712,713,714,715,716,717,718,719,720,721,722,723,724,725,726,727,728,
84675729,730,731,732,733,734,735,736,737,738,739,740,741,742,743,744,745,746,
84676747,748,749,750,751,752,753,754,755,756,757,758,759,760,761,762,763,764,
84677765,766,767,768,769,770,771,772,773,774,775,776,777,778,779,780,781,782,
84678783,784,785,786,787,788,789,790,791,792,793,794,795,796,797,798,799,800,
84679801,802,803,804,805,806,807,808,809,810,811,812,813,814,815,816,817,818,
84680819,820,821,822,823,824,825,826,827,828,829,830,831,832,833,834,835,836,
84681921,838,839,840,841,842,843,844,845,846,847,848,849,850,851,852,853,854,
84682855,856,857,858,859,860,861,862,863,864,865,866,867,868,869,870,871,872,
84683873,874,875,876,877,878,879,880,880,882,882,884,885,886,886,888,889,890,
846841021,1022,1023,894,895,896,897,898,899,900,901,902,903,904,905,906,907,908,
84685909,910,911,912,913,914,915,916,917,918,919,920,921,922,923,924,925,926,
84686927,928,929,930,931,932,933,934,935,936,937,938,939,902,904,905,906,944,
84687913,914,915,916,917,918,919,920,921,922,923,924,925,926,927,928,929,931,
84688931,932,933,934,935,936,937,938,939,908,910,911,975,914,920,978,979,980,
84689934,928,975,984,984,986,986,988,988,990,990,992,992,994,994,996,996,998,
84690998,1000,1000,1002,1002,1004,1004,1006,1006,922,929,1017,895,1012,917,1014,
846911015,1015,1017,1018,1018,1020,1021,1022,1023,1024,1025,1026,1027,1028,1029,
846921030,1031,1032,1033,1034,1035,1036,1037,1038,1039,1040,1041,1042,1043,1044,
846931045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,1058,1059,
846941060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1040,1041,1042,
846951043,1044,1045,1046,1047,1048,1049,1050,1051,1052,1053,1054,1055,1056,1057,
846961058,1059,1060,1061,1062,1063,1064,1065,1066,1067,1068,1069,1070,1071,1024,
846971025,1026,1027,1028,1029,1030,1031,1032,1033,1034,1035,1036,1037,1038,1039,
846981120,1120,1122,1122,1124,1124,1126,1126,1128,1128,1130,1130,1132,1132,1134,
846991134,1136,1136,1138,1138,1140,1140,1142,1142,1144,1144,1146,1146,1148,1148,
847001150,1150,1152,1152,1154,1155,1156,1157,1158,1159,1160,1161,1162,1162,1164,
847011164,1166,1166,1168,1168,1170,1170,1172,1172,1174,1174,1176,1176,1178,1178,
847021180,1180,1182,1182,1184,1184,1186,1186,1188,1188,1190,1190,1192,1192,1194,
847031194,1196,1196,1198,1198,1200,1200,1202,1202,1204,1204,1206,1206,1208,1208,
847041210,1210,1212,1212,1214,1214,1216,1217,1217,1219,1219,1221,1221,1223,1223,
847051225,1225,1227,1227,1229,1229,1216,1232,1232,1234,1234,1236,1236,1238,1238,
847061240,1240,1242,1242,1244,1244,1246,1246,1248,1248,1250,1250,1252,1252,1254,
847071254,1256,1256,1258,1258,1260,1260,1262,1262,1264,1264,1266,1266,1268,1268,
847081270,1270,1272,1272,1274,1274,1276,1276,1278,1278,1280,1280,1282,1282,1284,
847091284,1286,1286,1288,1288,1290,1290,1292,1292,1294,1294,1296,1296,1298,1298,
847101300,1300,1302,1302,1304,1304,1306,1306,1308,1308,1310,1310,1312,1312,1314,
847111314,1316,1316,1318,1318,1320,1320,1322,1322,1324,1324,1326,1326,1328,1329,
847121330,1331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341,1342,1343,1344,
847131345,1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,1357,1358,1359,
847141360,1361,1362,1363,1364,1365,1366,1367,1368,1369,1370,1371,1372,1373,1374,
847151375,1376,1329,1330,1331,1332,1333,1334,1335,1336,1337,1338,1339,1340,1341,
847161342,1343,1344,1345,1346,1347,1348,1349,1350,1351,1352,1353,1354,1355,1356,
847171357,1358,1359,1360,1361,1362,1363,1364,1365,1366,1415,1416,1417,1418,1419,
847181420,1421,1422,1423,1424,1425,1426,1427,1428,1429,1430,1431,1432,1433,1434,
847191435,1436,1437,1438,1439,1440,1441,1442,1443,1444,1445,1446,1447,1448,1449,
847201450,1451,1452,1453,1454,1455,1456,1457,1458,1459,1460,1461,1462,1463,1464,
847211465,1466,1467,1468,1469,1470,1471,1472,1473,1474,1475,1476,1477,1478,1479,
847221480,1481,1482,1483,1484,1485,1486,1487,1488,1489,1490,1491,1492,1493,1494,
847231495,1496,1497,1498,1499,1500,1501,1502,1503,1504,1505,1506,1507,1508,1509,
847241510,1511,1512,1513,1514,1515,1516,1517,1518,1519,1520,1521,1522,1523,1524,
847251525,1526,1527,1528,1529,1530,1531,1532,1533,1534,1535,1536,1537,1538,1539,
847261540,1541,1542,1543,1544,1545,1546,1547,1548,1549,1550,1551,1552,1553,1554,
847271555,1556,1557,1558,1559,1560,1561,1562,1563,1564,1565,1566,1567,1568,1569,
847281570,1571,1572,1573,1574,1575,1576,1577,1578,1579,1580,1581,1582,1583,1584,
847291585,1586,1587,1588,1589,1590,1591,1592,1593,1594,1595,1596,1597,1598,1599,
847301600,1601,1602,1603,1604,1605,1606,1607,1608,1609,1610,1611,1612,1613,1614,
847311615,1616,1617,1618,1619,1620,1621,1622,1623,1624,1625,1626,1627,1628,1629,
847321630,1631,1632,1633,1634,1635,1636,1637,1638,1639,1640,1641,1642,1643,1644,
847331645,1646,1647,1648,1649,1650,1651,1652,1653,1654,1655,1656,1657,1658,1659,
847341660,1661,1662,1663,1664,1665,1666,1667,1668,1669,1670,1671,1672,1673,1674,
847351675,1676,1677,1678,1679,1680,1681,1682,1683,1684,1685,1686,1687,1688,1689,
847361690,1691,1692,1693,1694,1695,1696,1697,1698,1699,1700,1701,1702,1703,1704,
847371705,1706,1707,1708,1709,1710,1711,1712,1713,1714,1715,1716,1717,1718,1719,
847381720,1721,1722,1723,1724,1725,1726,1727,1728,1729,1730,1731,1732,1733,1734,
847391735,1736,1737,1738,1739,1740,1741,1742,1743,1744,1745,1746,1747,1748,1749,
847401750,1751,1752,1753,1754,1755,1756,1757,1758,1759,1760,1761,1762,1763,1764,
847411765,1766,1767,1768,1769,1770,1771,1772,1773,1774,1775,1776,1777,1778,1779,
847421780,1781,1782,1783,1784,1785,1786,1787,1788,1789,1790,1791,1792,1793,1794,
847431795,1796,1797,1798,1799,1800,1801,1802,1803,1804,1805,1806,1807,1808,1809,
847441810,1811,1812,1813,1814,1815,1816,1817,1818,1819,1820,1821,1822,1823,1824,
847451825,1826,1827,1828,1829,1830,1831,1832,1833,1834,1835,1836,1837,1838,1839,
847461840,1841,1842,1843,1844,1845,1846,1847,1848,1849,1850,1851,1852,1853,1854,
847471855,1856,1857,1858,1859,1860,1861,1862,1863,1864,1865,1866,1867,1868,1869,
847481870,1871,1872,1873,1874,1875,1876,1877,1878,1879,1880,1881,1882,1883,1884,
847491885,1886,1887,1888,1889,1890,1891,1892,1893,1894,1895,1896,1897,1898,1899,
847501900,1901,1902,1903,1904,1905,1906,1907,1908,1909,1910,1911,1912,1913,1914,
847511915,1916,1917,1918,1919,1920,1921,1922,1923,1924,1925,1926,1927,1928,1929,
847521930,1931,1932,1933,1934,1935,1936,1937,1938,1939,1940,1941,1942,1943,1944,
847531945,1946,1947,1948,1949,1950,1951,1952,1953,1954,1955,1956,1957,1958,1959,
847541960,1961,1962,1963,1964,1965,1966,1967,1968,1969,1970,1971,1972,1973,1974,
847551975,1976,1977,1978,1979,1980,1981,1982,1983,1984,1985,1986,1987,1988,1989,
847561990,1991,1992,1993,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,
847572005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,
847582020,2021,2022,2023,2024,2025,2026,2027,2028,2029,2030,2031,2032,2033,2034,
847592035,2036,2037,2038,2039,2040,2041,2042,2043,2044,2045,2046,2047,2048,2049,
847602050,2051,2052,2053,2054,2055,2056,2057,2058,2059,2060,2061,2062,2063,2064,
847612065,2066,2067,2068,2069,2070,2071,2072,2073,2074,2075,2076,2077,2078,2079,
847622080,2081,2082,2083,2084,2085,2086,2087,2088,2089,2090,2091,2092,2093,2094,
847632095,2096,2097,2098,2099,2100,2101,2102,2103,2104,2105,2106,2107,2108,2109,
847642110,2111,2112,2113,2114,2115,2116,2117,2118,2119,2120,2121,2122,2123,2124,
847652125,2126,2127,2128,2129,2130,2131,2132,2133,2134,2135,2136,2137,2138,2139,
847662140,2141,2142,2143,2144,2145,2146,2147,2148,2149,2150,2151,2152,2153,2154,
847672155,2156,2157,2158,2159,2160,2161,2162,2163,2164,2165,2166,2167,2168,2169,
847682170,2171,2172,2173,2174,2175,2176,2177,2178,2179,2180,2181,2182,2183,2184,
847692185,2186,2187,2188,2189,2190,2191,2192,2193,2194,2195,2196,2197,2198,2199,
847702200,2201,2202,2203,2204,2205,2206,2207,2208,2209,2210,2211,2212,2213,2214,
847712215,2216,2217,2218,2219,2220,2221,2222,2223,2224,2225,2226,2227,2228,2229,
847722230,2231,2232,2233,2234,2235,2236,2237,2238,2239,2240,2241,2242,2243,2244,
847732245,2246,2247,2248,2249,2250,2251,2252,2253,2254,2255,2256,2257,2258,2259,
847742260,2261,2262,2263,2264,2265,2266,2267,2268,2269,2270,2271,2272,2273,2274,
847752275,2276,2277,2278,2279,2280,2281,2282,2283,2284,2285,2286,2287,2288,2289,
847762290,2291,2292,2293,2294,2295,2296,2297,2298,2299,2300,2301,2302,2303,2304,
847772305,2306,2307,2308,2309,2310,2311,2312,2313,2314,2315,2316,2317,2318,2319,
847782320,2321,2322,2323,2324,2325,2326,2327,2328,2329,2330,2331,2332,2333,2334,
847792335,2336,2337,2338,2339,2340,2341,2342,2343,2344,2345,2346,2347,2348,2349,
847802350,2351,2352,2353,2354,2355,2356,2357,2358,2359,2360,2361,2362,2363,2364,
847812365,2366,2367,2368,2369,2370,2371,2372,2373,2374,2375,2376,2377,2378,2379,
847822380,2381,2382,2383,2384,2385,2386,2387,2388,2389,2390,2391,2392,2393,2394,
847832395,2396,2397,2398,2399,2400,2401,2402,2403,2404,2405,2406,2407,2408,2409,
847842410,2411,2412,2413,2414,2415,2416,2417,2418,2419,2420,2421,2422,2423,2424,
847852425,2426,2427,2428,2429,2430,2431,2432,2433,2434,2435,2436,2437,2438,2439,
847862440,2441,2442,2443,2444,2445,2446,2447,2448,2449,2450,2451,2452,2453,2454,
847872455,2456,2457,2458,2459,2460,2461,2462,2463,2464,2465,2466,2467,2468,2469,
847882470,2471,2472,2473,2474,2475,2476,2477,2478,2479,2480,2481,2482,2483,2484,
847892485,2486,2487,2488,2489,2490,2491,2492,2493,2494,2495,2496,2497,2498,2499,
847902500,2501,2502,2503,2504,2505,2506,2507,2508,2509,2510,2511,2512,2513,2514,
847912515,2516,2517,2518,2519,2520,2521,2522,2523,2524,2525,2526,2527,2528,2529,
847922530,2531,2532,2533,2534,2535,2536,2537,2538,2539,2540,2541,2542,2543,2544,
847932545,2546,2547,2548,2549,2550,2551,2552,2553,2554,2555,2556,2557,2558,2559,
847942560,2561,2562,2563,2564,2565,2566,2567,2568,2569,2570,2571,2572,2573,2574,
847952575,2576,2577,2578,2579,2580,2581,2582,2583,2584,2585,2586,2587,2588,2589,
847962590,2591,2592,2593,2594,2595,2596,2597,2598,2599,2600,2601,2602,2603,2604,
847972605,2606,2607,2608,2609,2610,2611,2612,2613,2614,2615,2616,2617,2618,2619,
847982620,2621,2622,2623,2624,2625,2626,2627,2628,2629,2630,2631,2632,2633,2634,
847992635,2636,2637,2638,2639,2640,2641,2642,2643,2644,2645,2646,2647,2648,2649,
848002650,2651,2652,2653,2654,2655,2656,2657,2658,2659,2660,2661,2662,2663,2664,
848012665,2666,2667,2668,2669,2670,2671,2672,2673,2674,2675,2676,2677,2678,2679,
848022680,2681,2682,2683,2684,2685,2686,2687,2688,2689,2690,2691,2692,2693,2694,
848032695,2696,2697,2698,2699,2700,2701,2702,2703,2704,2705,2706,2707,2708,2709,
848042710,2711,2712,2713,2714,2715,2716,2717,2718,2719,2720,2721,2722,2723,2724,
848052725,2726,2727,2728,2729,2730,2731,2732,2733,2734,2735,2736,2737,2738,2739,
848062740,2741,2742,2743,2744,2745,2746,2747,2748,2749,2750,2751,2752,2753,2754,
848072755,2756,2757,2758,2759,2760,2761,2762,2763,2764,2765,2766,2767,2768,2769,
848082770,2771,2772,2773,2774,2775,2776,2777,2778,2779,2780,2781,2782,2783,2784,
848092785,2786,2787,2788,2789,2790,2791,2792,2793,2794,2795,2796,2797,2798,2799,
848102800,2801,2802,2803,2804,2805,2806,2807,2808,2809,2810,2811,2812,2813,2814,
848112815,2816,2817,2818,2819,2820,2821,2822,2823,2824,2825,2826,2827,2828,2829,
848122830,2831,2832,2833,2834,2835,2836,2837,2838,2839,2840,2841,2842,2843,2844,
848132845,2846,2847,2848,2849,2850,2851,2852,2853,2854,2855,2856,2857,2858,2859,
848142860,2861,2862,2863,2864,2865,2866,2867,2868,2869,2870,2871,2872,2873,2874,
848152875,2876,2877,2878,2879,2880,2881,2882,2883,2884,2885,2886,2887,2888,2889,
848162890,2891,2892,2893,2894,2895,2896,2897,2898,2899,2900,2901,2902,2903,2904,
848172905,2906,2907,2908,2909,2910,2911,2912,2913,2914,2915,2916,2917,2918,2919,
848182920,2921,2922,2923,2924,2925,2926,2927,2928,2929,2930,2931,2932,2933,2934,
848192935,2936,2937,2938,2939,2940,2941,2942,2943,2944,2945,2946,2947,2948,2949,
848202950,2951,2952,2953,2954,2955,2956,2957,2958,2959,2960,2961,2962,2963,2964,
848212965,2966,2967,2968,2969,2970,2971,2972,2973,2974,2975,2976,2977,2978,2979,
848222980,2981,2982,2983,2984,2985,2986,2987,2988,2989,2990,2991,2992,2993,2994,
848232995,2996,2997,2998,2999,3000,3001,3002,3003,3004,3005,3006,3007,3008,3009,
848243010,3011,3012,3013,3014,3015,3016,3017,3018,3019,3020,3021,3022,3023,3024,
848253025,3026,3027,3028,3029,3030,3031,3032,3033,3034,3035,3036,3037,3038,3039,
848263040,3041,3042,3043,3044,3045,3046,3047,3048,3049,3050,3051,3052,3053,3054,
848273055,3056,3057,3058,3059,3060,3061,3062,3063,3064,3065,3066,3067,3068,3069,
848283070,3071,3072,3073,3074,3075,3076,3077,3078,3079,3080,3081,3082,3083,3084,
848293085,3086,3087,3088,3089,3090,3091,3092,3093,3094,3095,3096,3097,3098,3099,
848303100,3101,3102,3103,3104,3105,3106,3107,3108,3109,3110,3111,3112,3113,3114,
848313115,3116,3117,3118,3119,3120,3121,3122,3123,3124,3125,3126,3127,3128,3129,
848323130,3131,3132,3133,3134,3135,3136,3137,3138,3139,3140,3141,3142,3143,3144,
848333145,3146,3147,3148,3149,3150,3151,3152,3153,3154,3155,3156,3157,3158,3159,
848343160,3161,3162,3163,3164,3165,3166,3167,3168,3169,3170,3171,3172,3173,3174,
848353175,3176,3177,3178,3179,3180,3181,3182,3183,3184,3185,3186,3187,3188,3189,
848363190,3191,3192,3193,3194,3195,3196,3197,3198,3199,3200,3201,3202,3203,3204,
848373205,3206,3207,3208,3209,3210,3211,3212,3213,3214,3215,3216,3217,3218,3219,
848383220,3221,3222,3223,3224,3225,3226,3227,3228,3229,3230,3231,3232,3233,3234,
848393235,3236,3237,3238,3239,3240,3241,3242,3243,3244,3245,3246,3247,3248,3249,
848403250,3251,3252,3253,3254,3255,3256,3257,3258,3259,3260,3261,3262,3263,3264,
848413265,3266,3267,3268,3269,3270,3271,3272,3273,3274,3275,3276,3277,3278,3279,
848423280,3281,3282,3283,3284,3285,3286,3287,3288,3289,3290,3291,3292,3293,3294,
848433295,3296,3297,3298,3299,3300,3301,3302,3303,3304,3305,3306,3307,3308,3309,
848443310,3311,3312,3313,3314,3315,3316,3317,3318,3319,3320,3321,3322,3323,3324,
848453325,3326,3327,3328,3329,3330,3331,3332,3333,3334,3335,3336,3337,3338,3339,
848463340,3341,3342,3343,3344,3345,3346,3347,3348,3349,3350,3351,3352,3353,3354,
848473355,3356,3357,3358,3359,3360,3361,3362,3363,3364,3365,3366,3367,3368,3369,
848483370,3371,3372,3373,3374,3375,3376,3377,3378,3379,3380,3381,3382,3383,3384,
848493385,3386,3387,3388,3389,3390,3391,3392,3393,3394,3395,3396,3397,3398,3399,
848503400,3401,3402,3403,3404,3405,3406,3407,3408,3409,3410,3411,3412,3413,3414,
848513415,3416,3417,3418,3419,3420,3421,3422,3423,3424,3425,3426,3427,3428,3429,
848523430,3431,3432,3433,3434,3435,3436,3437,3438,3439,3440,3441,3442,3443,3444,
848533445,3446,3447,3448,3449,3450,3451,3452,3453,3454,3455,3456,3457,3458,3459,
848543460,3461,3462,3463,3464,3465,3466,3467,3468,3469,3470,3471,3472,3473,3474,
848553475,3476,3477,3478,3479,3480,3481,3482,3483,3484,3485,3486,3487,3488,3489,
848563490,3491,3492,3493,3494,3495,3496,3497,3498,3499,3500,3501,3502,3503,3504,
848573505,3506,3507,3508,3509,3510,3511,3512,3513,3514,3515,3516,3517,3518,3519,
848583520,3521,3522,3523,3524,3525,3526,3527,3528,3529,3530,3531,3532,3533,3534,
848593535,3536,3537,3538,3539,3540,3541,3542,3543,3544,3545,3546,3547,3548,3549,
848603550,3551,3552,3553,3554,3555,3556,3557,3558,3559,3560,3561,3562,3563,3564,
848613565,3566,3567,3568,3569,3570,3571,3572,3573,3574,3575,3576,3577,3578,3579,
848623580,3581,3582,3583,3584,3585,3586,3587,3588,3589,3590,3591,3592,3593,3594,
848633595,3596,3597,3598,3599,3600,3601,3602,3603,3604,3605,3606,3607,3608,3609,
848643610,3611,3612,3613,3614,3615,3616,3617,3618,3619,3620,3621,3622,3623,3624,
848653625,3626,3627,3628,3629,3630,3631,3632,3633,3634,3635,3636,3637,3638,3639,
848663640,3641,3642,3643,3644,3645,3646,3647,3648,3649,3650,3651,3652,3653,3654,
848673655,3656,3657,3658,3659,3660,3661,3662,3663,3664,3665,3666,3667,3668,3669,
848683670,3671,3672,3673,3674,3675,3676,3677,3678,3679,3680,3681,3682,3683,3684,
848693685,3686,3687,3688,3689,3690,3691,3692,3693,3694,3695,3696,3697,3698,3699,
848703700,3701,3702,3703,3704,3705,3706,3707,3708,3709,3710,3711,3712,3713,3714,
848713715,3716,3717,3718,3719,3720,3721,3722,3723,3724,3725,3726,3727,3728,3729,
848723730,3731,3732,3733,3734,3735,3736,3737,3738,3739,3740,3741,3742,3743,3744,
848733745,3746,3747,3748,3749,3750,3751,3752,3753,3754,3755,3756,3757,3758,3759,
848743760,3761,3762,3763,3764,3765,3766,3767,3768,3769,3770,3771,3772,3773,3774,
848753775,3776,3777,3778,3779,3780,3781,3782,3783,3784,3785,3786,3787,3788,3789,
848763790,3791,3792,3793,3794,3795,3796,3797,3798,3799,3800,3801,3802,3803,3804,
848773805,3806,3807,3808,3809,3810,3811,3812,3813,3814,3815,3816,3817,3818,3819,
848783820,3821,3822,3823,3824,3825,3826,3827,3828,3829,3830,3831,3832,3833,3834,
848793835,3836,3837,3838,3839,3840,3841,3842,3843,3844,3845,3846,3847,3848,3849,
848803850,3851,3852,3853,3854,3855,3856,3857,3858,3859,3860,3861,3862,3863,3864,
848813865,3866,3867,3868,3869,3870,3871,3872,3873,3874,3875,3876,3877,3878,3879,
848823880,3881,3882,3883,3884,3885,3886,3887,3888,3889,3890,3891,3892,3893,3894,
848833895,3896,3897,3898,3899,3900,3901,3902,3903,3904,3905,3906,3907,3908,3909,
848843910,3911,3912,3913,3914,3915,3916,3917,3918,3919,3920,3921,3922,3923,3924,
848853925,3926,3927,3928,3929,3930,3931,3932,3933,3934,3935,3936,3937,3938,3939,
848863940,3941,3942,3943,3944,3945,3946,3947,3948,3949,3950,3951,3952,3953,3954,
848873955,3956,3957,3958,3959,3960,3961,3962,3963,3964,3965,3966,3967,3968,3969,
848883970,3971,3972,3973,3974,3975,3976,3977,3978,3979,3980,3981,3982,3983,3984,
848893985,3986,3987,3988,3989,3990,3991,3992,3993,3994,3995,3996,3997,3998,3999,
848904000,4001,4002,4003,4004,4005,4006,4007,4008,4009,4010,4011,4012,4013,4014,
848914015,4016,4017,4018,4019,4020,4021,4022,4023,4024,4025,4026,4027,4028,4029,
848924030,4031,4032,4033,4034,4035,4036,4037,4038,4039,4040,4041,4042,4043,4044,
848934045,4046,4047,4048,4049,4050,4051,4052,4053,4054,4055,4056,4057,4058,4059,
848944060,4061,4062,4063,4064,4065,4066,4067,4068,4069,4070,4071,4072,4073,4074,
848954075,4076,4077,4078,4079,4080,4081,4082,4083,4084,4085,4086,4087,4088,4089,
848964090,4091,4092,4093,4094,4095,4096,4097,4098,4099,4100,4101,4102,4103,4104,
848974105,4106,4107,4108,4109,4110,4111,4112,4113,4114,4115,4116,4117,4118,4119,
848984120,4121,4122,4123,4124,4125,4126,4127,4128,4129,4130,4131,4132,4133,4134,
848994135,4136,4137,4138,4139,4140,4141,4142,4143,4144,4145,4146,4147,4148,4149,
849004150,4151,4152,4153,4154,4155,4156,4157,4158,4159,4160,4161,4162,4163,4164,
849014165,4166,4167,4168,4169,4170,4171,4172,4173,4174,4175,4176,4177,4178,4179,
849024180,4181,4182,4183,4184,4185,4186,4187,4188,4189,4190,4191,4192,4193,4194,
849034195,4196,4197,4198,4199,4200,4201,4202,4203,4204,4205,4206,4207,4208,4209,
849044210,4211,4212,4213,4214,4215,4216,4217,4218,4219,4220,4221,4222,4223,4224,
849054225,4226,4227,4228,4229,4230,4231,4232,4233,4234,4235,4236,4237,4238,4239,
849064240,4241,4242,4243,4244,4245,4246,4247,4248,4249,4250,4251,4252,4253,4254,
849074255,4256,4257,4258,4259,4260,4261,4262,4263,4264,4265,4266,4267,4268,4269,
849084270,4271,4272,4273,4274,4275,4276,4277,4278,4279,4280,4281,4282,4283,4284,
849094285,4286,4287,4288,4289,4290,4291,4292,4293,4294,4295,4296,4297,4298,4299,
849104300,4301,4302,4303,4304,4305,4306,4307,4308,4309,4310,4311,4312,4313,4314,
849114315,4316,4317,4318,4319,4320,4321,4322,4323,4324,4325,4326,4327,4328,4329,
849124330,4331,4332,4333,4334,4335,4336,4337,4338,4339,4340,4341,4342,4343,4344,
849134345,4346,4347,4348,4349,4350,4351,4352,4353,4354,4355,4356,4357,4358,4359,
849144360,4361,4362,4363,4364,4365,4366,4367,4368,4369,4370,4371,4372,4373,4374,
849154375,4376,4377,4378,4379,4380,4381,4382,4383,4384,4385,4386,4387,4388,4389,
849164390,4391,4392,4393,4394,4395,4396,4397,4398,4399,4400,4401,4402,4403,4404,
849174405,4406,4407,4408,4409,4410,4411,4412,4413,4414,4415,4416,4417,4418,4419,
849184420,4421,4422,4423,4424,4425,4426,4427,4428,4429,4430,4431,4432,4433,4434,
849194435,4436,4437,4438,4439,4440,4441,4442,4443,4444,4445,4446,4447,4448,4449,
849204450,4451,4452,4453,4454,4455,4456,4457,4458,4459,4460,4461,4462,4463,4464,
849214465,4466,4467,4468,4469,4470,4471,4472,4473,4474,4475,4476,4477,4478,4479,
849224480,4481,4482,4483,4484,4485,4486,4487,4488,4489,4490,4491,4492,4493,4494,
849234495,4496,4497,4498,4499,4500,4501,4502,4503,4504,4505,4506,4507,4508,4509,
849244510,4511,4512,4513,4514,4515,4516,4517,4518,4519,4520,4521,4522,4523,4524,
849254525,4526,4527,4528,4529,4530,4531,4532,4533,4534,4535,4536,4537,4538,4539,
849264540,4541,4542,4543,4544,4545,4546,4547,4548,4549,4550,4551,4552,4553,4554,
849274555,4556,4557,4558,4559,4560,4561,4562,4563,4564,4565,4566,4567,4568,4569,
849284570,4571,4572,4573,4574,4575,4576,4577,4578,4579,4580,4581,4582,4583,4584,
849294585,4586,4587,4588,4589,4590,4591,4592,4593,4594,4595,4596,4597,4598,4599,
849304600,4601,4602,4603,4604,4605,4606,4607,4608,4609,4610,4611,4612,4613,4614,
849314615,4616,4617,4618,4619,4620,4621,4622,4623,4624,4625,4626,4627,4628,4629,
849324630,4631,4632,4633,4634,4635,4636,4637,4638,4639,4640,4641,4642,4643,4644,
849334645,4646,4647,4648,4649,4650,4651,4652,4653,4654,4655,4656,4657,4658,4659,
849344660,4661,4662,4663,4664,4665,4666,4667,4668,4669,4670,4671,4672,4673,4674,
849354675,4676,4677,4678,4679,4680,4681,4682,4683,4684,4685,4686,4687,4688,4689,
849364690,4691,4692,4693,4694,4695,4696,4697,4698,4699,4700,4701,4702,4703,4704,
849374705,4706,4707,4708,4709,4710,4711,4712,4713,4714,4715,4716,4717,4718,4719,
849384720,4721,4722,4723,4724,4725,4726,4727,4728,4729,4730,4731,4732,4733,4734,
849394735,4736,4737,4738,4739,4740,4741,4742,4743,4744,4745,4746,4747,4748,4749,
849404750,4751,4752,4753,4754,4755,4756,4757,4758,4759,4760,4761,4762,4763,4764,
849414765,4766,4767,4768,4769,4770,4771,4772,4773,4774,4775,4776,4777,4778,4779,
849424780,4781,4782,4783,4784,4785,4786,4787,4788,4789,4790,4791,4792,4793,4794,
849434795,4796,4797,4798,4799,4800,4801,4802,4803,4804,4805,4806,4807,4808,4809,
849444810,4811,4812,4813,4814,4815,4816,4817,4818,4819,4820,4821,4822,4823,4824,
849454825,4826,4827,4828,4829,4830,4831,4832,4833,4834,4835,4836,4837,4838,4839,
849464840,4841,4842,4843,4844,4845,4846,4847,4848,4849,4850,4851,4852,4853,4854,
849474855,4856,4857,4858,4859,4860,4861,4862,4863,4864,4865,4866,4867,4868,4869,
849484870,4871,4872,4873,4874,4875,4876,4877,4878,4879,4880,4881,4882,4883,4884,
849494885,4886,4887,4888,4889,4890,4891,4892,4893,4894,4895,4896,4897,4898,4899,
849504900,4901,4902,4903,4904,4905,4906,4907,4908,4909,4910,4911,4912,4913,4914,
849514915,4916,4917,4918,4919,4920,4921,4922,4923,4924,4925,4926,4927,4928,4929,
849524930,4931,4932,4933,4934,4935,4936,4937,4938,4939,4940,4941,4942,4943,4944,
849534945,4946,4947,4948,4949,4950,4951,4952,4953,4954,4955,4956,4957,4958,4959,
849544960,4961,4962,4963,4964,4965,4966,4967,4968,4969,4970,4971,4972,4973,4974,
849554975,4976,4977,4978,4979,4980,4981,4982,4983,4984,4985,4986,4987,4988,4989,
849564990,4991,4992,4993,4994,4995,4996,4997,4998,4999,5000,5001,5002,5003,5004,
849575005,5006,5007,5008,5009,5010,5011,5012,5013,5014,5015,5016,5017,5018,5019,
849585020,5021,5022,5023,5024,5025,5026,5027,5028,5029,5030,5031,5032,5033,5034,
849595035,5036,5037,5038,5039,5040,5041,5042,5043,5044,5045,5046,5047,5048,5049,
849605050,5051,5052,5053,5054,5055,5056,5057,5058,5059,5060,5061,5062,5063,5064,
849615065,5066,5067,5068,5069,5070,5071,5072,5073,5074,5075,5076,5077,5078,5079,
849625080,5081,5082,5083,5084,5085,5086,5087,5088,5089,5090,5091,5092,5093,5094,
849635095,5096,5097,5098,5099,5100,5101,5102,5103,5104,5105,5106,5107,5108,5109,
849645110,5111,5104,5105,5106,5107,5108,5109,5118,5119,5120,5121,5122,5123,5124,
849655125,5126,5127,5128,5129,5130,5131,5132,5133,5134,5135,5136,5137,5138,5139,
849665140,5141,5142,5143,5144,5145,5146,5147,5148,5149,5150,5151,5152,5153,5154,
849675155,5156,5157,5158,5159,5160,5161,5162,5163,5164,5165,5166,5167,5168,5169,
849685170,5171,5172,5173,5174,5175,5176,5177,5178,5179,5180,5181,5182,5183,5184,
849695185,5186,5187,5188,5189,5190,5191,5192,5193,5194,5195,5196,5197,5198,5199,
849705200,5201,5202,5203,5204,5205,5206,5207,5208,5209,5210,5211,5212,5213,5214,
849715215,5216,5217,5218,5219,5220,5221,5222,5223,5224,5225,5226,5227,5228,5229,
849725230,5231,5232,5233,5234,5235,5236,5237,5238,5239,5240,5241,5242,5243,5244,
849735245,5246,5247,5248,5249,5250,5251,5252,5253,5254,5255,5256,5257,5258,5259,
849745260,5261,5262,5263,5264,5265,5266,5267,5268,5269,5270,5271,5272,5273,5274,
849755275,5276,5277,5278,5279,5280,5281,5282,5283,5284,5285,5286,5287,5288,5289,
849765290,5291,5292,5293,5294,5295,5296,5297,5298,5299,5300,5301,5302,5303,5304,
849775305,5306,5307,5308,5309,5310,5311,5312,5313,5314,5315,5316,5317,5318,5319,
849785320,5321,5322,5323,5324,5325,5326,5327,5328,5329,5330,5331,5332,5333,5334,
849795335,5336,5337,5338,5339,5340,5341,5342,5343,5344,5345,5346,5347,5348,5349,
849805350,5351,5352,5353,5354,5355,5356,5357,5358,5359,5360,5361,5362,5363,5364,
849815365,5366,5367,5368,5369,5370,5371,5372,5373,5374,5375,5376,5377,5378,5379,
849825380,5381,5382,5383,5384,5385,5386,5387,5388,5389,5390,5391,5392,5393,5394,
849835395,5396,5397,5398,5399,5400,5401,5402,5403,5404,5405,5406,5407,5408,5409,
849845410,5411,5412,5413,5414,5415,5416,5417,5418,5419,5420,5421,5422,5423,5424,
849855425,5426,5427,5428,5429,5430,5431,5432,5433,5434,5435,5436,5437,5438,5439,
849865440,5441,5442,5443,5444,5445,5446,5447,5448,5449,5450,5451,5452,5453,5454,
849875455,5456,5457,5458,5459,5460,5461,5462,5463,5464,5465,5466,5467,5468,5469,
849885470,5471,5472,5473,5474,5475,5476,5477,5478,5479,5480,5481,5482,5483,5484,
849895485,5486,5487,5488,5489,5490,5491,5492,5493,5494,5495,5496,5497,5498,5499,
849905500,5501,5502,5503,5504,5505,5506,5507,5508,5509,5510,5511,5512,5513,5514,
849915515,5516,5517,5518,5519,5520,5521,5522,5523,5524,5525,5526,5527,5528,5529,
849925530,5531,5532,5533,5534,5535,5536,5537,5538,5539,5540,5541,5542,5543,5544,
849935545,5546,5547,5548,5549,5550,5551,5552,5553,5554,5555,5556,5557,5558,5559,
849945560,5561,5562,5563,5564,5565,5566,5567,5568,5569,5570,5571,5572,5573,5574,
849955575,5576,5577,5578,5579,5580,5581,5582,5583,5584,5585,5586,5587,5588,5589,
849965590,5591,5592,5593,5594,5595,5596,5597,5598,5599,5600,5601,5602,5603,5604,
849975605,5606,5607,5608,5609,5610,5611,5612,5613,5614,5615,5616,5617,5618,5619,
849985620,5621,5622,5623,5624,5625,5626,5627,5628,5629,5630,5631,5632,5633,5634,
849995635,5636,5637,5638,5639,5640,5641,5642,5643,5644,5645,5646,5647,5648,5649,
850005650,5651,5652,5653,5654,5655,5656,5657,5658,5659,5660,5661,5662,5663,5664,
850015665,5666,5667,5668,5669,5670,5671,5672,5673,5674,5675,5676,5677,5678,5679,
850025680,5681,5682,5683,5684,5685,5686,5687,5688,5689,5690,5691,5692,5693,5694,
850035695,5696,5697,5698,5699,5700,5701,5702,5703,5704,5705,5706,5707,5708,5709,
850045710,5711,5712,5713,5714,5715,5716,5717,5718,5719,5720,5721,5722,5723,5724,
850055725,5726,5727,5728,5729,5730,5731,5732,5733,5734,5735,5736,5737,5738,5739,
850065740,5741,5742,5743,5744,5745,5746,5747,5748,5749,5750,5751,5752,5753,5754,
850075755,5756,5757,5758,5759,5760,5761,5762,5763,5764,5765,5766,5767,5768,5769,
850085770,5771,5772,5773,5774,5775,5776,5777,5778,5779,5780,5781,5782,5783,5784,
850095785,5786,5787,5788,5789,5790,5791,5792,5793,5794,5795,5796,5797,5798,5799,
850105800,5801,5802,5803,5804,5805,5806,5807,5808,5809,5810,5811,5812,5813,5814,
850115815,5816,5817,5818,5819,5820,5821,5822,5823,5824,5825,5826,5827,5828,5829,
850125830,5831,5832,5833,5834,5835,5836,5837,5838,5839,5840,5841,5842,5843,5844,
850135845,5846,5847,5848,5849,5850,5851,5852,5853,5854,5855,5856,5857,5858,5859,
850145860,5861,5862,5863,5864,5865,5866,5867,5868,5869,5870,5871,5872,5873,5874,
850155875,5876,5877,5878,5879,5880,5881,5882,5883,5884,5885,5886,5887,5888,5889,
850165890,5891,5892,5893,5894,5895,5896,5897,5898,5899,5900,5901,5902,5903,5904,
850175905,5906,5907,5908,5909,5910,5911,5912,5913,5914,5915,5916,5917,5918,5919,
850185920,5921,5922,5923,5924,5925,5926,5927,5928,5929,5930,5931,5932,5933,5934,
850195935,5936,5937,5938,5939,5940,5941,5942,5943,5944,5945,5946,5947,5948,5949,
850205950,5951,5952,5953,5954,5955,5956,5957,5958,5959,5960,5961,5962,5963,5964,
850215965,5966,5967,5968,5969,5970,5971,5972,5973,5974,5975,5976,5977,5978,5979,
850225980,5981,5982,5983,5984,5985,5986,5987,5988,5989,5990,5991,5992,5993,5994,
850235995,5996,5997,5998,5999,6000,6001,6002,6003,6004,6005,6006,6007,6008,6009,
850246010,6011,6012,6013,6014,6015,6016,6017,6018,6019,6020,6021,6022,6023,6024,
850256025,6026,6027,6028,6029,6030,6031,6032,6033,6034,6035,6036,6037,6038,6039,
850266040,6041,6042,6043,6044,6045,6046,6047,6048,6049,6050,6051,6052,6053,6054,
850276055,6056,6057,6058,6059,6060,6061,6062,6063,6064,6065,6066,6067,6068,6069,
850286070,6071,6072,6073,6074,6075,6076,6077,6078,6079,6080,6081,6082,6083,6084,
850296085,6086,6087,6088,6089,6090,6091,6092,6093,6094,6095,6096,6097,6098,6099,
850306100,6101,6102,6103,6104,6105,6106,6107,6108,6109,6110,6111,6112,6113,6114,
850316115,6116,6117,6118,6119,6120,6121,6122,6123,6124,6125,6126,6127,6128,6129,
850326130,6131,6132,6133,6134,6135,6136,6137,6138,6139,6140,6141,6142,6143,6144,
850336145,6146,6147,6148,6149,6150,6151,6152,6153,6154,6155,6156,6157,6158,6159,
850346160,6161,6162,6163,6164,6165,6166,6167,6168,6169,6170,6171,6172,6173,6174,
850356175,6176,6177,6178,6179,6180,6181,6182,6183,6184,6185,6186,6187,6188,6189,
850366190,6191,6192,6193,6194,6195,6196,6197,6198,6199,6200,6201,6202,6203,6204,
850376205,6206,6207,6208,6209,6210,6211,6212,6213,6214,6215,6216,6217,6218,6219,
850386220,6221,6222,6223,6224,6225,6226,6227,6228,6229,6230,6231,6232,6233,6234,
850396235,6236,6237,6238,6239,6240,6241,6242,6243,6244,6245,6246,6247,6248,6249,
850406250,6251,6252,6253,6254,6255,6256,6257,6258,6259,6260,6261,6262,6263,6264,
850416265,6266,6267,6268,6269,6270,6271,6272,6273,6274,6275,6276,6277,6278,6279,
850426280,6281,6282,6283,6284,6285,6286,6287,6288,6289,6290,6291,6292,6293,6294,
850436295,6296,6297,6298,6299,6300,6301,6302,6303,6304,6305,6306,6307,6308,6309,
850446310,6311,6312,6313,6314,6315,6316,6317,6318,6319,6320,6321,6322,6323,6324,
850456325,6326,6327,6328,6329,6330,6331,6332,6333,6334,6335,6336,6337,6338,6339,
850466340,6341,6342,6343,6344,6345,6346,6347,6348,6349,6350,6351,6352,6353,6354,
850476355,6356,6357,6358,6359,6360,6361,6362,6363,6364,6365,6366,6367,6368,6369,
850486370,6371,6372,6373,6374,6375,6376,6377,6378,6379,6380,6381,6382,6383,6384,
850496385,6386,6387,6388,6389,6390,6391,6392,6393,6394,6395,6396,6397,6398,6399,
850506400,6401,6402,6403,6404,6405,6406,6407,6408,6409,6410,6411,6412,6413,6414,
850516415,6416,6417,6418,6419,6420,6421,6422,6423,6424,6425,6426,6427,6428,6429,
850526430,6431,6432,6433,6434,6435,6436,6437,6438,6439,6440,6441,6442,6443,6444,
850536445,6446,6447,6448,6449,6450,6451,6452,6453,6454,6455,6456,6457,6458,6459,
850546460,6461,6462,6463,6464,6465,6466,6467,6468,6469,6470,6471,6472,6473,6474,
850556475,6476,6477,6478,6479,6480,6481,6482,6483,6484,6485,6486,6487,6488,6489,
850566490,6491,6492,6493,6494,6495,6496,6497,6498,6499,6500,6501,6502,6503,6504,
850576505,6506,6507,6508,6509,6510,6511,6512,6513,6514,6515,6516,6517,6518,6519,
850586520,6521,6522,6523,6524,6525,6526,6527,6528,6529,6530,6531,6532,6533,6534,
850596535,6536,6537,6538,6539,6540,6541,6542,6543,6544,6545,6546,6547,6548,6549,
850606550,6551,6552,6553,6554,6555,6556,6557,6558,6559,6560,6561,6562,6563,6564,
850616565,6566,6567,6568,6569,6570,6571,6572,6573,6574,6575,6576,6577,6578,6579,
850626580,6581,6582,6583,6584,6585,6586,6587,6588,6589,6590,6591,6592,6593,6594,
850636595,6596,6597,6598,6599,6600,6601,6602,6603,6604,6605,6606,6607,6608,6609,
850646610,6611,6612,6613,6614,6615,6616,6617,6618,6619,6620,6621,6622,6623,6624,
850656625,6626,6627,6628,6629,6630,6631,6632,6633,6634,6635,6636,6637,6638,6639,
850666640,6641,6642,6643,6644,6645,6646,6647,6648,6649,6650,6651,6652,6653,6654,
850676655,6656,6657,6658,6659,6660,6661,6662,6663,6664,6665,6666,6667,6668,6669,
850686670,6671,6672,6673,6674,6675,6676,6677,6678,6679,6680,6681,6682,6683,6684,
850696685,6686,6687,6688,6689,6690,6691,6692,6693,6694,6695,6696,6697,6698,6699,
850706700,6701,6702,6703,6704,6705,6706,6707,6708,6709,6710,6711,6712,6713,6714,
850716715,6716,6717,6718,6719,6720,6721,6722,6723,6724,6725,6726,6727,6728,6729,
850726730,6731,6732,6733,6734,6735,6736,6737,6738,6739,6740,6741,6742,6743,6744,
850736745,6746,6747,6748,6749,6750,6751,6752,6753,6754,6755,6756,6757,6758,6759,
850746760,6761,6762,6763,6764,6765,6766,6767,6768,6769,6770,6771,6772,6773,6774,
850756775,6776,6777,6778,6779,6780,6781,6782,6783,6784,6785,6786,6787,6788,6789,
850766790,6791,6792,6793,6794,6795,6796,6797,6798,6799,6800,6801,6802,6803,6804,
850776805,6806,6807,6808,6809,6810,6811,6812,6813,6814,6815,6816,6817,6818,6819,
850786820,6821,6822,6823,6824,6825,6826,6827,6828,6829,6830,6831,6832,6833,6834,
850796835,6836,6837,6838,6839,6840,6841,6842,6843,6844,6845,6846,6847,6848,6849,
850806850,6851,6852,6853,6854,6855,6856,6857,6858,6859,6860,6861,6862,6863,6864,
850816865,6866,6867,6868,6869,6870,6871,6872,6873,6874,6875,6876,6877,6878,6879,
850826880,6881,6882,6883,6884,6885,6886,6887,6888,6889,6890,6891,6892,6893,6894,
850836895,6896,6897,6898,6899,6900,6901,6902,6903,6904,6905,6906,6907,6908,6909,
850846910,6911,6912,6913,6914,6915,6916,6917,6918,6919,6920,6921,6922,6923,6924,
850856925,6926,6927,6928,6929,6930,6931,6932,6933,6934,6935,6936,6937,6938,6939,
850866940,6941,6942,6943,6944,6945,6946,6947,6948,6949,6950,6951,6952,6953,6954,
850876955,6956,6957,6958,6959,6960,6961,6962,6963,6964,6965,6966,6967,6968,6969,
850886970,6971,6972,6973,6974,6975,6976,6977,6978,6979,6980,6981,6982,6983,6984,
850896985,6986,6987,6988,6989,6990,6991,6992,6993,6994,6995,6996,6997,6998,6999,
850907000,7001,7002,7003,7004,7005,7006,7007,7008,7009,7010,7011,7012,7013,7014,
850917015,7016,7017,7018,7019,7020,7021,7022,7023,7024,7025,7026,7027,7028,7029,
850927030,7031,7032,7033,7034,7035,7036,7037,7038,7039,7040,7041,7042,7043,7044,
850937045,7046,7047,7048,7049,7050,7051,7052,7053,7054,7055,7056,7057,7058,7059,
850947060,7061,7062,7063,7064,7065,7066,7067,7068,7069,7070,7071,7072,7073,7074,
850957075,7076,7077,7078,7079,7080,7081,7082,7083,7084,7085,7086,7087,7088,7089,
850967090,7091,7092,7093,7094,7095,7096,7097,7098,7099,7100,7101,7102,7103,7104,
850977105,7106,7107,7108,7109,7110,7111,7112,7113,7114,7115,7116,7117,7118,7119,
850987120,7121,7122,7123,7124,7125,7126,7127,7128,7129,7130,7131,7132,7133,7134,
850997135,7136,7137,7138,7139,7140,7141,7142,7143,7144,7145,7146,7147,7148,7149,
851007150,7151,7152,7153,7154,7155,7156,7157,7158,7159,7160,7161,7162,7163,7164,
851017165,7166,7167,7168,7169,7170,7171,7172,7173,7174,7175,7176,7177,7178,7179,
851027180,7181,7182,7183,7184,7185,7186,7187,7188,7189,7190,7191,7192,7193,7194,
851037195,7196,7197,7198,7199,7200,7201,7202,7203,7204,7205,7206,7207,7208,7209,
851047210,7211,7212,7213,7214,7215,7216,7217,7218,7219,7220,7221,7222,7223,7224,
851057225,7226,7227,7228,7229,7230,7231,7232,7233,7234,7235,7236,7237,7238,7239,
851067240,7241,7242,7243,7244,7245,7246,7247,7248,7249,7250,7251,7252,7253,7254,
851077255,7256,7257,7258,7259,7260,7261,7262,7263,7264,7265,7266,7267,7268,7269,
851087270,7271,7272,7273,7274,7275,7276,7277,7278,7279,7280,7281,7282,7283,7284,
851097285,7286,7287,7288,7289,7290,7291,7292,7293,7294,7295,1042,1044,1054,1057,
851101058,1058,1066,1122,42570L,7305,7306,7307,7308,7309,7310,7311,7312,7313,
851117314,7315,7316,7317,7318,7319,7320,7321,7322,7323,7324,7325,7326,7327,7328,
851127329,7330,7331,7332,7333,7334,7335,7336,7337,7338,7339,7340,7341,7342,7343,
851137344,7345,7346,7347,7348,7349,7350,7351,7352,7353,7354,7355,7356,7357,7358,
851147359,7360,7361,7362,7363,7364,7365,7366,7367,7368,7369,7370,7371,7372,7373,
851157374,7375,7376,7377,7378,7379,7380,7381,7382,7383,7384,7385,7386,7387,7388,
851167389,7390,7391,7392,7393,7394,7395,7396,7397,7398,7399,7400,7401,7402,7403,
851177404,7405,7406,7407,7408,7409,7410,7411,7412,7413,7414,7415,7416,7417,7418,
851187419,7420,7421,7422,7423,7424,7425,7426,7427,7428,7429,7430,7431,7432,7433,
851197434,7435,7436,7437,7438,7439,7440,7441,7442,7443,7444,7445,7446,7447,7448,
851207449,7450,7451,7452,7453,7454,7455,7456,7457,7458,7459,7460,7461,7462,7463,
851217464,7465,7466,7467,7468,7469,7470,7471,7472,7473,7474,7475,7476,7477,7478,
851227479,7480,7481,7482,7483,7484,7485,7486,7487,7488,7489,7490,7491,7492,7493,
851237494,7495,7496,7497,7498,7499,7500,7501,7502,7503,7504,7505,7506,7507,7508,
851247509,7510,7511,7512,7513,7514,7515,7516,7517,7518,7519,7520,7521,7522,7523,
851257524,7525,7526,7527,7528,7529,7530,7531,7532,7533,7534,7535,7536,7537,7538,
851267539,7540,7541,7542,7543,7544,42877L,7546,7547,7548,11363,7550,7551,7552,
851277553,7554,7555,7556,7557,7558,7559,7560,7561,7562,7563,7564,7565,7566,7567,
851287568,7569,7570,7571,7572,7573,7574,7575,7576,7577,7578,7579,7580,7581,7582,
851297583,7584,7585,7586,7587,7588,7589,7590,7591,7592,7593,7594,7595,7596,7597,
851307598,7599,7600,7601,7602,7603,7604,7605,7606,7607,7608,7609,7610,7611,7612,
851317613,7614,7615,7616,7617,7618,7619,7620,7621,7622,7623,7624,7625,7626,7627,
851327628,7629,7630,7631,7632,7633,7634,7635,7636,7637,7638,7639,7640,7641,7642,
851337643,7644,7645,7646,7647,7648,7649,7650,7651,7652,7653,7654,7655,7656,7657,
851347658,7659,7660,7661,7662,7663,7664,7665,7666,7667,7668,7669,7670,7671,7672,
851357673,7674,7675,7676,7677,7678,7679,7680,7680,7682,7682,7684,7684,7686,7686,
851367688,7688,7690,7690,7692,7692,7694,7694,7696,7696,7698,7698,7700,7700,7702,
851377702,7704,7704,7706,7706,7708,7708,7710,7710,7712,7712,7714,7714,7716,7716,
851387718,7718,7720,7720,7722,7722,7724,7724,7726,7726,7728,7728,7730,7730,7732,
851397732,7734,7734,7736,7736,7738,7738,7740,7740,7742,7742,7744,7744,7746,7746,
851407748,7748,7750,7750,7752,7752,7754,7754,7756,7756,7758,7758,7760,7760,7762,
851417762,7764,7764,7766,7766,7768,7768,7770,7770,7772,7772,7774,7774,7776,7776,
851427778,7778,7780,7780,7782,7782,7784,7784,7786,7786,7788,7788,7790,7790,7792,
851437792,7794,7794,7796,7796,7798,7798,7800,7800,7802,7802,7804,7804,7806,7806,
851447808,7808,7810,7810,7812,7812,7814,7814,7816,7816,7818,7818,7820,7820,7822,
851457822,7824,7824,7826,7826,7828,7828,7830,7831,7832,7833,7834,7776,7836,7837,
851467838,7839,7840,7840,7842,7842,7844,7844,7846,7846,7848,7848,7850,7850,7852,
851477852,7854,7854,7856,7856,7858,7858,7860,7860,7862,7862,7864,7864,7866,7866,
851487868,7868,7870,7870,7872,7872,7874,7874,7876,7876,7878,7878,7880,7880,7882,
851497882,7884,7884,7886,7886,7888,7888,7890,7890,7892,7892,7894,7894,7896,7896,
851507898,7898,7900,7900,7902,7902,7904,7904,7906,7906,7908,7908,7910,7910,7912,
851517912,7914,7914,7916,7916,7918,7918,7920,7920,7922,7922,7924,7924,7926,7926,
851527928,7928,7930,7930,7932,7932,7934,7934,7944,7945,7946,7947,7948,7949,7950,
851537951,7944,7945,7946,7947,7948,7949,7950,7951,7960,7961,7962,7963,7964,7965,
851547958,7959,7960,7961,7962,7963,7964,7965,7966,7967,7976,7977,7978,7979,7980,
851557981,7982,7983,7976,7977,7978,7979,7980,7981,7982,7983,7992,7993,7994,7995,
851567996,7997,7998,7999,7992,7993,7994,7995,7996,7997,7998,7999,8008,8009,8010,
851578011,8012,8013,8006,8007,8008,8009,8010,8011,8012,8013,8014,8015,8016,8025,
851588018,8027,8020,8029,8022,8031,8024,8025,8026,8027,8028,8029,8030,8031,8040,
851598041,8042,8043,8044,8045,8046,8047,8040,8041,8042,8043,8044,8045,8046,8047,
851608122,8123,8136,8137,8138,8139,8154,8155,8184,8185,8170,8171,8186,8187,8062,
851618063,8064,8065,8066,8067,8068,8069,8070,8071,8072,8073,8074,8075,8076,8077,
851628078,8079,8080,8081,8082,8083,8084,8085,8086,8087,8088,8089,8090,8091,8092,
851638093,8094,8095,8096,8097,8098,8099,8100,8101,8102,8103,8104,8105,8106,8107,
851648108,8109,8110,8111,8120,8121,8114,8115,8116,8117,8118,8119,8120,8121,8122,
851658123,8124,8125,921,8127,8128,8129,8130,8131,8132,8133,8134,8135,8136,8137,
851668138,8139,8140,8141,8142,8143,8152,8153,8146,8147,8148,8149,8150,8151,8152,
851678153,8154,8155,8156,8157,8158,8159,8168,8169,8162,8163,8164,8172,8166,8167,
851688168,8169,8170,8171,8172,8173,8174,8175,8176,8177,8178,8179,8180,8181,8182,
851698183,8184,8185,8186,8187,8188,8189,8190,8191,8192,8193,8194,8195,8196,8197,
851708198,8199,8200,8201,8202,8203,8204,8205,8206,8207,8208,8209,8210,8211,8212,
851718213,8214,8215,8216,8217,8218,8219,8220,8221,8222,8223,8224,8225,8226,8227,
851728228,8229,8230,8231,8232,8233,8234,8235,8236,8237,8238,8239,8240,8241,8242,
851738243,8244,8245,8246,8247,8248,8249,8250,8251,8252,8253,8254,8255,8256,8257,
851748258,8259,8260,8261,8262,8263,8264,8265,8266,8267,8268,8269,8270,8271,8272,
851758273,8274,8275,8276,8277,8278,8279,8280,8281,8282,8283,8284,8285,8286,8287,
851768288,8289,8290,8291,8292,8293,8294,8295,8296,8297,8298,8299,8300,8301,8302,
851778303,8304,8305,8306,8307,8308,8309,8310,8311,8312,8313,8314,8315,8316,8317,
851788318,8319,8320,8321,8322,8323,8324,8325,8326,8327,8328,8329,8330,8331,8332,
851798333,8334,8335,8336,8337,8338,8339,8340,8341,8342,8343,8344,8345,8346,8347,
851808348,8349,8350,8351,8352,8353,8354,8355,8356,8357,8358,8359,8360,8361,8362,
851818363,8364,8365,8366,8367,8368,8369,8370,8371,8372,8373,8374,8375,8376,8377,
851828378,8379,8380,8381,8382,8383,8384,8385,8386,8387,8388,8389,8390,8391,8392,
851838393,8394,8395,8396,8397,8398,8399,8400,8401,8402,8403,8404,8405,8406,8407,
851848408,8409,8410,8411,8412,8413,8414,8415,8416,8417,8418,8419,8420,8421,8422,
851858423,8424,8425,8426,8427,8428,8429,8430,8431,8432,8433,8434,8435,8436,8437,
851868438,8439,8440,8441,8442,8443,8444,8445,8446,8447,8448,8449,8450,8451,8452,
851878453,8454,8455,8456,8457,8458,8459,8460,8461,8462,8463,8464,8465,8466,8467,
851888468,8469,8470,8471,8472,8473,8474,8475,8476,8477,8478,8479,8480,8481,8482,
851898483,8484,8485,8486,8487,8488,8489,8490,8491,8492,8493,8494,8495,8496,8497,
851908498,8499,8500,8501,8502,8503,8504,8505,8506,8507,8508,8509,8510,8511,8512,
851918513,8514,8515,8516,8517,8518,8519,8520,8521,8522,8523,8524,8525,8498,8527,
851928528,8529,8530,8531,8532,8533,8534,8535,8536,8537,8538,8539,8540,8541,8542,
851938543,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,8554,8555,8556,8557,
851948558,8559,8544,8545,8546,8547,8548,8549,8550,8551,8552,8553,8554,8555,8556,
851958557,8558,8559,8576,8577,8578,8579,8579,8581,8582,8583,8584,8585,8586,8587,
851968588,8589,8590,8591,8592,8593,8594,8595,8596,8597,8598,8599,8600,8601,8602,
851978603,8604,8605,8606,8607,8608,8609,8610,8611,8612,8613,8614,8615,8616,8617,
851988618,8619,8620,8621,8622,8623,8624,8625,8626,8627,8628,8629,8630,8631,8632,
851998633,8634,8635,8636,8637,8638,8639,8640,8641,8642,8643,8644,8645,8646,8647,
852008648,8649,8650,8651,8652,8653,8654,8655,8656,8657,8658,8659,8660,8661,8662,
852018663,8664,8665,8666,8667,8668,8669,8670,8671,8672,8673,8674,8675,8676,8677,
852028678,8679,8680,8681,8682,8683,8684,8685,8686,8687,8688,8689,8690,8691,8692,
852038693,8694,8695,8696,8697,8698,8699,8700,8701,8702,8703,8704,8705,8706,8707,
852048708,8709,8710,8711,8712,8713,8714,8715,8716,8717,8718,8719,8720,8721,8722,
852058723,8724,8725,8726,8727,8728,8729,8730,8731,8732,8733,8734,8735,8736,8737,
852068738,8739,8740,8741,8742,8743,8744,8745,8746,8747,8748,8749,8750,8751,8752,
852078753,8754,8755,8756,8757,8758,8759,8760,8761,8762,8763,8764,8765,8766,8767,
852088768,8769,8770,8771,8772,8773,8774,8775,8776,8777,8778,8779,8780,8781,8782,
852098783,8784,8785,8786,8787,8788,8789,8790,8791,8792,8793,8794,8795,8796,8797,
852108798,8799,8800,8801,8802,8803,8804,8805,8806,8807,8808,8809,8810,8811,8812,
852118813,8814,8815,8816,8817,8818,8819,8820,8821,8822,8823,8824,8825,8826,8827,
852128828,8829,8830,8831,8832,8833,8834,8835,8836,8837,8838,8839,8840,8841,8842,
852138843,8844,8845,8846,8847,8848,8849,8850,8851,8852,8853,8854,8855,8856,8857,
852148858,8859,8860,8861,8862,8863,8864,8865,8866,8867,8868,8869,8870,8871,8872,
852158873,8874,8875,8876,8877,8878,8879,8880,8881,8882,8883,8884,8885,8886,8887,
852168888,8889,8890,8891,8892,8893,8894,8895,8896,8897,8898,8899,8900,8901,8902,
852178903,8904,8905,8906,8907,8908,8909,8910,8911,8912,8913,8914,8915,8916,8917,
852188918,8919,8920,8921,8922,8923,8924,8925,8926,8927,8928,8929,8930,8931,8932,
852198933,8934,8935,8936,8937,8938,8939,8940,8941,8942,8943,8944,8945,8946,8947,
852208948,8949,8950,8951,8952,8953,8954,8955,8956,8957,8958,8959,8960,8961,8962,
852218963,8964,8965,8966,8967,8968,8969,8970,8971,8972,8973,8974,8975,8976,8977,
852228978,8979,8980,8981,8982,8983,8984,8985,8986,8987,8988,8989,8990,8991,8992,
852238993,8994,8995,8996,8997,8998,8999,9000,9001,9002,9003,9004,9005,9006,9007,
852249008,9009,9010,9011,9012,9013,9014,9015,9016,9017,9018,9019,9020,9021,9022,
852259023,9024,9025,9026,9027,9028,9029,9030,9031,9032,9033,9034,9035,9036,9037,
852269038,9039,9040,9041,9042,9043,9044,9045,9046,9047,9048,9049,9050,9051,9052,
852279053,9054,9055,9056,9057,9058,9059,9060,9061,9062,9063,9064,9065,9066,9067,
852289068,9069,9070,9071,9072,9073,9074,9075,9076,9077,9078,9079,9080,9081,9082,
852299083,9084,9085,9086,9087,9088,9089,9090,9091,9092,9093,9094,9095,9096,9097,
852309098,9099,9100,9101,9102,9103,9104,9105,9106,9107,9108,9109,9110,9111,9112,
852319113,9114,9115,9116,9117,9118,9119,9120,9121,9122,9123,9124,9125,9126,9127,
852329128,9129,9130,9131,9132,9133,9134,9135,9136,9137,9138,9139,9140,9141,9142,
852339143,9144,9145,9146,9147,9148,9149,9150,9151,9152,9153,9154,9155,9156,9157,
852349158,9159,9160,9161,9162,9163,9164,9165,9166,9167,9168,9169,9170,9171,9172,
852359173,9174,9175,9176,9177,9178,9179,9180,9181,9182,9183,9184,9185,9186,9187,
852369188,9189,9190,9191,9192,9193,9194,9195,9196,9197,9198,9199,9200,9201,9202,
852379203,9204,9205,9206,9207,9208,9209,9210,9211,9212,9213,9214,9215,9216,9217,
852389218,9219,9220,9221,9222,9223,9224,9225,9226,9227,9228,9229,9230,9231,9232,
852399233,9234,9235,9236,9237,9238,9239,9240,9241,9242,9243,9244,9245,9246,9247,
852409248,9249,9250,9251,9252,9253,9254,9255,9256,9257,9258,9259,9260,9261,9262,
852419263,9264,9265,9266,9267,9268,9269,9270,9271,9272,9273,9274,9275,9276,9277,
852429278,9279,9280,9281,9282,9283,9284,9285,9286,9287,9288,9289,9290,9291,9292,
852439293,9294,9295,9296,9297,9298,9299,9300,9301,9302,9303,9304,9305,9306,9307,
852449308,9309,9310,9311,9312,9313,9314,9315,9316,9317,9318,9319,9320,9321,9322,
852459323,9324,9325,9326,9327,9328,9329,9330,9331,9332,9333,9334,9335,9336,9337,
852469338,9339,9340,9341,9342,9343,9344,9345,9346,9347,9348,9349,9350,9351,9352,
852479353,9354,9355,9356,9357,9358,9359,9360,9361,9362,9363,9364,9365,9366,9367,
852489368,9369,9370,9371,9372,9373,9374,9375,9376,9377,9378,9379,9380,9381,9382,
852499383,9384,9385,9386,9387,9388,9389,9390,9391,9392,9393,9394,9395,9396,9397,
852509398,9399,9400,9401,9402,9403,9404,9405,9406,9407,9408,9409,9410,9411,9412,
852519413,9414,9415,9416,9417,9418,9419,9420,9421,9422,9423,9398,9399,9400,9401,
852529402,9403,9404,9405,9406,9407,9408,9409,9410,9411,9412,9413,9414,9415,9416,
852539417,9418,9419,9420,9421,9422,9423,9450,9451,9452,9453,9454,9455,9456,9457,
852549458,9459,9460,9461,9462,9463,9464,9465,9466,9467,9468,9469,9470,9471,9472,
852559473,9474,9475,9476,9477,9478,9479,9480,9481,9482,9483,9484,9485,9486,9487,
852569488,9489,9490,9491,9492,9493,9494,9495,9496,9497,9498,9499,9500,9501,9502,
852579503,9504,9505,9506,9507,9508,9509,9510,9511,9512,9513,9514,9515,9516,9517,
852589518,9519,9520,9521,9522,9523,9524,9525,9526,9527,9528,9529,9530,9531,9532,
852599533,9534,9535,9536,9537,9538,9539,9540,9541,9542,9543,9544,9545,9546,9547,
852609548,9549,9550,9551,9552,9553,9554,9555,9556,9557,9558,9559,9560,9561,9562,
852619563,9564,9565,9566,9567,9568,9569,9570,9571,9572,9573,9574,9575,9576,9577,
852629578,9579,9580,9581,9582,9583,9584,9585,9586,9587,9588,9589,9590,9591,9592,
852639593,9594,9595,9596,9597,9598,9599,9600,9601,9602,9603,9604,9605,9606,9607,
852649608,9609,9610,9611,9612,9613,9614,9615,9616,9617,9618,9619,9620,9621,9622,
852659623,9624,9625,9626,9627,9628,9629,9630,9631,9632,9633,9634,9635,9636,9637,
852669638,9639,9640,9641,9642,9643,9644,9645,9646,9647,9648,9649,9650,9651,9652,
852679653,9654,9655,9656,9657,9658,9659,9660,9661,9662,9663,9664,9665,9666,9667,
852689668,9669,9670,9671,9672,9673,9674,9675,9676,9677,9678,9679,9680,9681,9682,
852699683,9684,9685,9686,9687,9688,9689,9690,9691,9692,9693,9694,9695,9696,9697,
852709698,9699,9700,9701,9702,9703,9704,9705,9706,9707,9708,9709,9710,9711,9712,
852719713,9714,9715,9716,9717,9718,9719,9720,9721,9722,9723,9724,9725,9726,9727,
852729728,9729,9730,9731,9732,9733,9734,9735,9736,9737,9738,9739,9740,9741,9742,
852739743,9744,9745,9746,9747,9748,9749,9750,9751,9752,9753,9754,9755,9756,9757,
852749758,9759,9760,9761,9762,9763,9764,9765,9766,9767,9768,9769,9770,9771,9772,
852759773,9774,9775,9776,9777,9778,9779,9780,9781,9782,9783,9784,9785,9786,9787,
852769788,9789,9790,9791,9792,9793,9794,9795,9796,9797,9798,9799,9800,9801,9802,
852779803,9804,9805,9806,9807,9808,9809,9810,9811,9812,9813,9814,9815,9816,9817,
852789818,9819,9820,9821,9822,9823,9824,9825,9826,9827,9828,9829,9830,9831,9832,
852799833,9834,9835,9836,9837,9838,9839,9840,9841,9842,9843,9844,9845,9846,9847,
852809848,9849,9850,9851,9852,9853,9854,9855,9856,9857,9858,9859,9860,9861,9862,
852819863,9864,9865,9866,9867,9868,9869,9870,9871,9872,9873,9874,9875,9876,9877,
852829878,9879,9880,9881,9882,9883,9884,9885,9886,9887,9888,9889,9890,9891,9892,
852839893,9894,9895,9896,9897,9898,9899,9900,9901,9902,9903,9904,9905,9906,9907,
852849908,9909,9910,9911,9912,9913,9914,9915,9916,9917,9918,9919,9920,9921,9922,
852859923,9924,9925,9926,9927,9928,9929,9930,9931,9932,9933,9934,9935,9936,9937,
852869938,9939,9940,9941,9942,9943,9944,9945,9946,9947,9948,9949,9950,9951,9952,
852879953,9954,9955,9956,9957,9958,9959,9960,9961,9962,9963,9964,9965,9966,9967,
852889968,9969,9970,9971,9972,9973,9974,9975,9976,9977,9978,9979,9980,9981,9982,
852899983,9984,9985,9986,9987,9988,9989,9990,9991,9992,9993,9994,9995,9996,9997,
852909998,9999,10000,10001,10002,10003,10004,10005,10006,10007,10008,10009,
8529110010,10011,10012,10013,10014,10015,10016,10017,10018,10019,10020,10021,
8529210022,10023,10024,10025,10026,10027,10028,10029,10030,10031,10032,10033,
8529310034,10035,10036,10037,10038,10039,10040,10041,10042,10043,10044,10045,
8529410046,10047,10048,10049,10050,10051,10052,10053,10054,10055,10056,10057,
8529510058,10059,10060,10061,10062,10063,10064,10065,10066,10067,10068,10069,
8529610070,10071,10072,10073,10074,10075,10076,10077,10078,10079,10080,10081,
8529710082,10083,10084,10085,10086,10087,10088,10089,10090,10091,10092,10093,
8529810094,10095,10096,10097,10098,10099,10100,10101,10102,10103,10104,10105,
8529910106,10107,10108,10109,10110,10111,10112,10113,10114,10115,10116,10117,
8530010118,10119,10120,10121,10122,10123,10124,10125,10126,10127,10128,10129,
8530110130,10131,10132,10133,10134,10135,10136,10137,10138,10139,10140,10141,
8530210142,10143,10144,10145,10146,10147,10148,10149,10150,10151,10152,10153,
8530310154,10155,10156,10157,10158,10159,10160,10161,10162,10163,10164,10165,
8530410166,10167,10168,10169,10170,10171,10172,10173,10174,10175,10176,10177,
8530510178,10179,10180,10181,10182,10183,10184,10185,10186,10187,10188,10189,
8530610190,10191,10192,10193,10194,10195,10196,10197,10198,10199,10200,10201,
8530710202,10203,10204,10205,10206,10207,10208,10209,10210,10211,10212,10213,
8530810214,10215,10216,10217,10218,10219,10220,10221,10222,10223,10224,10225,
8530910226,10227,10228,10229,10230,10231,10232,10233,10234,10235,10236,10237,
8531010238,10239,10240,10241,10242,10243,10244,10245,10246,10247,10248,10249,
8531110250,10251,10252,10253,10254,10255,10256,10257,10258,10259,10260,10261,
8531210262,10263,10264,10265,10266,10267,10268,10269,10270,10271,10272,10273,
8531310274,10275,10276,10277,10278,10279,10280,10281,10282,10283,10284,10285,
8531410286,10287,10288,10289,10290,10291,10292,10293,10294,10295,10296,10297,
8531510298,10299,10300,10301,10302,10303,10304,10305,10306,10307,10308,10309,
8531610310,10311,10312,10313,10314,10315,10316,10317,10318,10319,10320,10321,
8531710322,10323,10324,10325,10326,10327,10328,10329,10330,10331,10332,10333,
8531810334,10335,10336,10337,10338,10339,10340,10341,10342,10343,10344,10345,
8531910346,10347,10348,10349,10350,10351,10352,10353,10354,10355,10356,10357,
8532010358,10359,10360,10361,10362,10363,10364,10365,10366,10367,10368,10369,
8532110370,10371,10372,10373,10374,10375,10376,10377,10378,10379,10380,10381,
8532210382,10383,10384,10385,10386,10387,10388,10389,10390,10391,10392,10393,
8532310394,10395,10396,10397,10398,10399,10400,10401,10402,10403,10404,10405,
8532410406,10407,10408,10409,10410,10411,10412,10413,10414,10415,10416,10417,
8532510418,10419,10420,10421,10422,10423,10424,10425,10426,10427,10428,10429,
8532610430,10431,10432,10433,10434,10435,10436,10437,10438,10439,10440,10441,
8532710442,10443,10444,10445,10446,10447,10448,10449,10450,10451,10452,10453,
8532810454,10455,10456,10457,10458,10459,10460,10461,10462,10463,10464,10465,
8532910466,10467,10468,10469,10470,10471,10472,10473,10474,10475,10476,10477,
8533010478,10479,10480,10481,10482,10483,10484,10485,10486,10487,10488,10489,
8533110490,10491,10492,10493,10494,10495,10496,10497,10498,10499,10500,10501,
8533210502,10503,10504,10505,10506,10507,10508,10509,10510,10511,10512,10513,
8533310514,10515,10516,10517,10518,10519,10520,10521,10522,10523,10524,10525,
8533410526,10527,10528,10529,10530,10531,10532,10533,10534,10535,10536,10537,
8533510538,10539,10540,10541,10542,10543,10544,10545,10546,10547,10548,10549,
8533610550,10551,10552,10553,10554,10555,10556,10557,10558,10559,10560,10561,
8533710562,10563,10564,10565,10566,10567,10568,10569,10570,10571,10572,10573,
8533810574,10575,10576,10577,10578,10579,10580,10581,10582,10583,10584,10585,
8533910586,10587,10588,10589,10590,10591,10592,10593,10594,10595,10596,10597,
8534010598,10599,10600,10601,10602,10603,10604,10605,10606,10607,10608,10609,
8534110610,10611,10612,10613,10614,10615,10616,10617,10618,10619,10620,10621,
8534210622,10623,10624,10625,10626,10627,10628,10629,10630,10631,10632,10633,
8534310634,10635,10636,10637,10638,10639,10640,10641,10642,10643,10644,10645,
8534410646,10647,10648,10649,10650,10651,10652,10653,10654,10655,10656,10657,
8534510658,10659,10660,10661,10662,10663,10664,10665,10666,10667,10668,10669,
8534610670,10671,10672,10673,10674,10675,10676,10677,10678,10679,10680,10681,
8534710682,10683,10684,10685,10686,10687,10688,10689,10690,10691,10692,10693,
8534810694,10695,10696,10697,10698,10699,10700,10701,10702,10703,10704,10705,
8534910706,10707,10708,10709,10710,10711,10712,10713,10714,10715,10716,10717,
8535010718,10719,10720,10721,10722,10723,10724,10725,10726,10727,10728,10729,
8535110730,10731,10732,10733,10734,10735,10736,10737,10738,10739,10740,10741,
8535210742,10743,10744,10745,10746,10747,10748,10749,10750,10751,10752,10753,
8535310754,10755,10756,10757,10758,10759,10760,10761,10762,10763,10764,10765,
8535410766,10767,10768,10769,10770,10771,10772,10773,10774,10775,10776,10777,
8535510778,10779,10780,10781,10782,10783,10784,10785,10786,10787,10788,10789,
8535610790,10791,10792,10793,10794,10795,10796,10797,10798,10799,10800,10801,
8535710802,10803,10804,10805,10806,10807,10808,10809,10810,10811,10812,10813,
8535810814,10815,10816,10817,10818,10819,10820,10821,10822,10823,10824,10825,
8535910826,10827,10828,10829,10830,10831,10832,10833,10834,10835,10836,10837,
8536010838,10839,10840,10841,10842,10843,10844,10845,10846,10847,10848,10849,
8536110850,10851,10852,10853,10854,10855,10856,10857,10858,10859,10860,10861,
8536210862,10863,10864,10865,10866,10867,10868,10869,10870,10871,10872,10873,
8536310874,10875,10876,10877,10878,10879,10880,10881,10882,10883,10884,10885,
8536410886,10887,10888,10889,10890,10891,10892,10893,10894,10895,10896,10897,
8536510898,10899,10900,10901,10902,10903,10904,10905,10906,10907,10908,10909,
8536610910,10911,10912,10913,10914,10915,10916,10917,10918,10919,10920,10921,
8536710922,10923,10924,10925,10926,10927,10928,10929,10930,10931,10932,10933,
8536810934,10935,10936,10937,10938,10939,10940,10941,10942,10943,10944,10945,
8536910946,10947,10948,10949,10950,10951,10952,10953,10954,10955,10956,10957,
8537010958,10959,10960,10961,10962,10963,10964,10965,10966,10967,10968,10969,
8537110970,10971,10972,10973,10974,10975,10976,10977,10978,10979,10980,10981,
8537210982,10983,10984,10985,10986,10987,10988,10989,10990,10991,10992,10993,
8537310994,10995,10996,10997,10998,10999,11000,11001,11002,11003,11004,11005,
8537411006,11007,11008,11009,11010,11011,11012,11013,11014,11015,11016,11017,
8537511018,11019,11020,11021,11022,11023,11024,11025,11026,11027,11028,11029,
8537611030,11031,11032,11033,11034,11035,11036,11037,11038,11039,11040,11041,
8537711042,11043,11044,11045,11046,11047,11048,11049,11050,11051,11052,11053,
8537811054,11055,11056,11057,11058,11059,11060,11061,11062,11063,11064,11065,
8537911066,11067,11068,11069,11070,11071,11072,11073,11074,11075,11076,11077,
8538011078,11079,11080,11081,11082,11083,11084,11085,11086,11087,11088,11089,
8538111090,11091,11092,11093,11094,11095,11096,11097,11098,11099,11100,11101,
8538211102,11103,11104,11105,11106,11107,11108,11109,11110,11111,11112,11113,
8538311114,11115,11116,11117,11118,11119,11120,11121,11122,11123,11124,11125,
8538411126,11127,11128,11129,11130,11131,11132,11133,11134,11135,11136,11137,
8538511138,11139,11140,11141,11142,11143,11144,11145,11146,11147,11148,11149,
8538611150,11151,11152,11153,11154,11155,11156,11157,11158,11159,11160,11161,
8538711162,11163,11164,11165,11166,11167,11168,11169,11170,11171,11172,11173,
8538811174,11175,11176,11177,11178,11179,11180,11181,11182,11183,11184,11185,
8538911186,11187,11188,11189,11190,11191,11192,11193,11194,11195,11196,11197,
8539011198,11199,11200,11201,11202,11203,11204,11205,11206,11207,11208,11209,
8539111210,11211,11212,11213,11214,11215,11216,11217,11218,11219,11220,11221,
8539211222,11223,11224,11225,11226,11227,11228,11229,11230,11231,11232,11233,
8539311234,11235,11236,11237,11238,11239,11240,11241,11242,11243,11244,11245,
8539411246,11247,11248,11249,11250,11251,11252,11253,11254,11255,11256,11257,
8539511258,11259,11260,11261,11262,11263,11264,11265,11266,11267,11268,11269,
8539611270,11271,11272,11273,11274,11275,11276,11277,11278,11279,11280,11281,
8539711282,11283,11284,11285,11286,11287,11288,11289,11290,11291,11292,11293,
8539811294,11295,11296,11297,11298,11299,11300,11301,11302,11303,11304,11305,
8539911306,11307,11308,11309,11310,11311,11264,11265,11266,11267,11268,11269,
8540011270,11271,11272,11273,11274,11275,11276,11277,11278,11279,11280,11281,
8540111282,11283,11284,11285,11286,11287,11288,11289,11290,11291,11292,11293,
8540211294,11295,11296,11297,11298,11299,11300,11301,11302,11303,11304,11305,
8540311306,11307,11308,11309,11310,11359,11360,11360,11362,11363,11364,570,574,
8540411367,11367,11369,11369,11371,11371,11373,11374,11375,11376,11377,11378,
8540511378,11380,11381,11381,11383,11384,11385,11386,11387,11388,11389,11390,
8540611391,11392,11392,11394,11394,11396,11396,11398,11398,11400,11400,11402,
8540711402,11404,11404,11406,11406,11408,11408,11410,11410,11412,11412,11414,
8540811414,11416,11416,11418,11418,11420,11420,11422,11422,11424,11424,11426,
8540911426,11428,11428,11430,11430,11432,11432,11434,11434,11436,11436,11438,
8541011438,11440,11440,11442,11442,11444,11444,11446,11446,11448,11448,11450,
8541111450,11452,11452,11454,11454,11456,11456,11458,11458,11460,11460,11462,
8541211462,11464,11464,11466,11466,11468,11468,11470,11470,11472,11472,11474,
8541311474,11476,11476,11478,11478,11480,11480,11482,11482,11484,11484,11486,
8541411486,11488,11488,11490,11490,11492,11493,11494,11495,11496,11497,11498,
8541511499,11499,11501,11501,11503,11504,11505,11506,11506,11508,11509,11510,
8541611511,11512,11513,11514,11515,11516,11517,11518,11519,4256,4257,4258,4259,
854174260,4261,4262,4263,4264,4265,4266,4267,4268,4269,4270,4271,4272,4273,4274,
854184275,4276,4277,4278,4279,4280,4281,4282,4283,4284,4285,4286,4287,4288,4289,
854194290,4291,4292,4293,11558,4295,11560,11561,11562,11563,11564,4301,11566,
8542011567,11568,11569,11570,11571,11572,11573,11574,11575,11576,11577,11578,
8542111579,11580,11581,11582,11583,11584,11585,11586,11587,11588,11589,11590,
8542211591,11592,11593,11594,11595,11596,11597,11598,11599,11600,11601,11602,
8542311603,11604,11605,11606,11607,11608,11609,11610,11611,11612,11613,11614,
8542411615,11616,11617,11618,11619,11620,11621,11622,11623,11624,11625,11626,
8542511627,11628,11629,11630,11631,11632,11633,11634,11635,11636,11637,11638,
8542611639,11640,11641,11642,11643,11644,11645,11646,11647,11648,11649,11650,
8542711651,11652,11653,11654,11655,11656,11657,11658,11659,11660,11661,11662,
8542811663,11664,11665,11666,11667,11668,11669,11670,11671,11672,11673,11674,
8542911675,11676,11677,11678,11679,11680,11681,11682,11683,11684,11685,11686,
8543011687,11688,11689,11690,11691,11692,11693,11694,11695,11696,11697,11698,
8543111699,11700,11701,11702,11703,11704,11705,11706,11707,11708,11709,11710,
8543211711,11712,11713,11714,11715,11716,11717,11718,11719,11720,11721,11722,
8543311723,11724,11725,11726,11727,11728,11729,11730,11731,11732,11733,11734,
8543411735,11736,11737,11738,11739,11740,11741,11742,11743,11744,11745,11746,
8543511747,11748,11749,11750,11751,11752,11753,11754,11755,11756,11757,11758,
8543611759,11760,11761,11762,11763,11764,11765,11766,11767,11768,11769,11770,
8543711771,11772,11773,11774,11775,11776,11777,11778,11779,11780,11781,11782,
8543811783,11784,11785,11786,11787,11788,11789,11790,11791,11792,11793,11794,
8543911795,11796,11797,11798,11799,11800,11801,11802,11803,11804,11805,11806,
8544011807,11808,11809,11810,11811,11812,11813,11814,11815,11816,11817,11818,
8544111819,11820,11821,11822,11823,11824,11825,11826,11827,11828,11829,11830,
8544211831,11832,11833,11834,11835,11836,11837,11838,11839,11840,11841,11842,
8544311843,11844,11845,11846,11847,11848,11849,11850,11851,11852,11853,11854,
8544411855,11856,11857,11858,11859,11860,11861,11862,11863,11864,11865,11866,
8544511867,11868,11869,11870,11871,11872,11873,11874,11875,11876,11877,11878,
8544611879,11880,11881,11882,11883,11884,11885,11886,11887,11888,11889,11890,
8544711891,11892,11893,11894,11895,11896,11897,11898,11899,11900,11901,11902,
8544811903,11904,11905,11906,11907,11908,11909,11910,11911,11912,11913,11914,
8544911915,11916,11917,11918,11919,11920,11921,11922,11923,11924,11925,11926,
8545011927,11928,11929,11930,11931,11932,11933,11934,11935,11936,11937,11938,
8545111939,11940,11941,11942,11943,11944,11945,11946,11947,11948,11949,11950,
8545211951,11952,11953,11954,11955,11956,11957,11958,11959,11960,11961,11962,
8545311963,11964,11965,11966,11967,11968,11969,11970,11971,11972,11973,11974,
8545411975,11976,11977,11978,11979,11980,11981,11982,11983,11984,11985,11986,
8545511987,11988,11989,11990,11991,11992,11993,11994,11995,11996,11997,11998,
8545611999,12000,12001,12002,12003,12004,12005,12006,12007,12008,12009,12010,
8545712011,12012,12013,12014,12015,12016,12017,12018,12019,12020,12021,12022,
8545812023,12024,12025,12026,12027,12028,12029,12030,12031,12032,12033,12034,
8545912035,12036,12037,12038,12039,12040,12041,12042,12043,12044,12045,12046,
8546012047,12048,12049,12050,12051,12052,12053,12054,12055,12056,12057,12058,
8546112059,12060,12061,12062,12063,12064,12065,12066,12067,12068,12069,12070,
8546212071,12072,12073,12074,12075,12076,12077,12078,12079,12080,12081,12082,
8546312083,12084,12085,12086,12087,12088,12089,12090,12091,12092,12093,12094,
8546412095,12096,12097,12098,12099,12100,12101,12102,12103,12104,12105,12106,
8546512107,12108,12109,12110,12111,12112,12113,12114,12115,12116,12117,12118,
8546612119,12120,12121,12122,12123,12124,12125,12126,12127,12128,12129,12130,
8546712131,12132,12133,12134,12135,12136,12137,12138,12139,12140,12141,12142,
8546812143,12144,12145,12146,12147,12148,12149,12150,12151,12152,12153,12154,
8546912155,12156,12157,12158,12159,12160,12161,12162,12163,12164,12165,12166,
8547012167,12168,12169,12170,12171,12172,12173,12174,12175,12176,12177,12178,
8547112179,12180,12181,12182,12183,12184,12185,12186,12187,12188,12189,12190,
8547212191,12192,12193,12194,12195,12196,12197,12198,12199,12200,12201,12202,
8547312203,12204,12205,12206,12207,12208,12209,12210,12211,12212,12213,12214,
8547412215,12216,12217,12218,12219,12220,12221,12222,12223,12224,12225,12226,
8547512227,12228,12229,12230,12231,12232,12233,12234,12235,12236,12237,12238,
8547612239,12240,12241,12242,12243,12244,12245,12246,12247,12248,12249,12250,
8547712251,12252,12253,12254,12255,12256,12257,12258,12259,12260,12261,12262,
8547812263,12264,12265,12266,12267,12268,12269,12270,12271,12272,12273,12274,
8547912275,12276,12277,12278,12279,12280,12281,12282,12283,12284,12285,12286,
8548012287,12288,12289,12290,12291,12292,12293,12294,12295,12296,12297,12298,
8548112299,12300,12301,12302,12303,12304,12305,12306,12307,12308,12309,12310,
8548212311,12312,12313,12314,12315,12316,12317,12318,12319,12320,12321,12322,
8548312323,12324,12325,12326,12327,12328,12329,12330,12331,12332,12333,12334,
8548412335,12336,12337,12338,12339,12340,12341,12342,12343,12344,12345,12346,
8548512347,12348,12349,12350,12351,12352,12353,12354,12355,12356,12357,12358,
8548612359,12360,12361,12362,12363,12364,12365,12366,12367,12368,12369,12370,
8548712371,12372,12373,12374,12375,12376,12377,12378,12379,12380,12381,12382,
8548812383,12384,12385,12386,12387,12388,12389,12390,12391,12392,12393,12394,
8548912395,12396,12397,12398,12399,12400,12401,12402,12403,12404,12405,12406,
8549012407,12408,12409,12410,12411,12412,12413,12414,12415,12416,12417,12418,
8549112419,12420,12421,12422,12423,12424,12425,12426,12427,12428,12429,12430,
8549212431,12432,12433,12434,12435,12436,12437,12438,12439,12440,12441,12442,
8549312443,12444,12445,12446,12447,12448,12449,12450,12451,12452,12453,12454,
8549412455,12456,12457,12458,12459,12460,12461,12462,12463,12464,12465,12466,
8549512467,12468,12469,12470,12471,12472,12473,12474,12475,12476,12477,12478,
8549612479,12480,12481,12482,12483,12484,12485,12486,12487,12488,12489,12490,
8549712491,12492,12493,12494,12495,12496,12497,12498,12499,12500,12501,12502,
8549812503,12504,12505,12506,12507,12508,12509,12510,12511,12512,12513,12514,
8549912515,12516,12517,12518,12519,12520,12521,12522,12523,12524,12525,12526,
8550012527,12528,12529,12530,12531,12532,12533,12534,12535,12536,12537,12538,
8550112539,12540,12541,12542,12543,12544,12545,12546,12547,12548,12549,12550,
8550212551,12552,12553,12554,12555,12556,12557,12558,12559,12560,12561,12562,
8550312563,12564,12565,12566,12567,12568,12569,12570,12571,12572,12573,12574,
8550412575,12576,12577,12578,12579,12580,12581,12582,12583,12584,12585,12586,
8550512587,12588,12589,12590,12591,12592,12593,12594,12595,12596,12597,12598,
8550612599,12600,12601,12602,12603,12604,12605,12606,12607,12608,12609,12610,
8550712611,12612,12613,12614,12615,12616,12617,12618,12619,12620,12621,12622,
8550812623,12624,12625,12626,12627,12628,12629,12630,12631,12632,12633,12634,
8550912635,12636,12637,12638,12639,12640,12641,12642,12643,12644,12645,12646,
8551012647,12648,12649,12650,12651,12652,12653,12654,12655,12656,12657,12658,
8551112659,12660,12661,12662,12663,12664,12665,12666,12667,12668,12669,12670,
8551212671,12672,12673,12674,12675,12676,12677,12678,12679,12680,12681,12682,
8551312683,12684,12685,12686,12687,12688,12689,12690,12691,12692,12693,12694,
8551412695,12696,12697,12698,12699,12700,12701,12702,12703,12704,12705,12706,
8551512707,12708,12709,12710,12711,12712,12713,12714,12715,12716,12717,12718,
8551612719,12720,12721,12722,12723,12724,12725,12726,12727,12728,12729,12730,
8551712731,12732,12733,12734,12735,12736,12737,12738,12739,12740,12741,12742,
8551812743,12744,12745,12746,12747,12748,12749,12750,12751,12752,12753,12754,
8551912755,12756,12757,12758,12759,12760,12761,12762,12763,12764,12765,12766,
8552012767,12768,12769,12770,12771,12772,12773,12774,12775,12776,12777,12778,
8552112779,12780,12781,12782,12783,12784,12785,12786,12787,12788,12789,12790,
8552212791,12792,12793,12794,12795,12796,12797,12798,12799,12800,12801,12802,
8552312803,12804,12805,12806,12807,12808,12809,12810,12811,12812,12813,12814,
8552412815,12816,12817,12818,12819,12820,12821,12822,12823,12824,12825,12826,
8552512827,12828,12829,12830,12831,12832,12833,12834,12835,12836,12837,12838,
8552612839,12840,12841,12842,12843,12844,12845,12846,12847,12848,12849,12850,
8552712851,12852,12853,12854,12855,12856,12857,12858,12859,12860,12861,12862,
8552812863,12864,12865,12866,12867,12868,12869,12870,12871,12872,12873,12874,
8552912875,12876,12877,12878,12879,12880,12881,12882,12883,12884,12885,12886,
8553012887,12888,12889,12890,12891,12892,12893,12894,12895,12896,12897,12898,
8553112899,12900,12901,12902,12903,12904,12905,12906,12907,12908,12909,12910,
8553212911,12912,12913,12914,12915,12916,12917,12918,12919,12920,12921,12922,
8553312923,12924,12925,12926,12927,12928,12929,12930,12931,12932,12933,12934,
8553412935,12936,12937,12938,12939,12940,12941,12942,12943,12944,12945,12946,
8553512947,12948,12949,12950,12951,12952,12953,12954,12955,12956,12957,12958,
8553612959,12960,12961,12962,12963,12964,12965,12966,12967,12968,12969,12970,
8553712971,12972,12973,12974,12975,12976,12977,12978,12979,12980,12981,12982,
8553812983,12984,12985,12986,12987,12988,12989,12990,12991,12992,12993,12994,
8553912995,12996,12997,12998,12999,13000,13001,13002,13003,13004,13005,13006,
8554013007,13008,13009,13010,13011,13012,13013,13014,13015,13016,13017,13018,
8554113019,13020,13021,13022,13023,13024,13025,13026,13027,13028,13029,13030,
8554213031,13032,13033,13034,13035,13036,13037,13038,13039,13040,13041,13042,
8554313043,13044,13045,13046,13047,13048,13049,13050,13051,13052,13053,13054,
8554413055,13056,13057,13058,13059,13060,13061,13062,13063,13064,13065,13066,
8554513067,13068,13069,13070,13071,13072,13073,13074,13075,13076,13077,13078,
8554613079,13080,13081,13082,13083,13084,13085,13086,13087,13088,13089,13090,
8554713091,13092,13093,13094,13095,13096,13097,13098,13099,13100,13101,13102,
8554813103,13104,13105,13106,13107,13108,13109,13110,13111,13112,13113,13114,
8554913115,13116,13117,13118,13119,13120,13121,13122,13123,13124,13125,13126,
8555013127,13128,13129,13130,13131,13132,13133,13134,13135,13136,13137,13138,
8555113139,13140,13141,13142,13143,13144,13145,13146,13147,13148,13149,13150,
8555213151,13152,13153,13154,13155,13156,13157,13158,13159,13160,13161,13162,
8555313163,13164,13165,13166,13167,13168,13169,13170,13171,13172,13173,13174,
8555413175,13176,13177,13178,13179,13180,13181,13182,13183,13184,13185,13186,
8555513187,13188,13189,13190,13191,13192,13193,13194,13195,13196,13197,13198,
8555613199,13200,13201,13202,13203,13204,13205,13206,13207,13208,13209,13210,
8555713211,13212,13213,13214,13215,13216,13217,13218,13219,13220,13221,13222,
8555813223,13224,13225,13226,13227,13228,13229,13230,13231,13232,13233,13234,
8555913235,13236,13237,13238,13239,13240,13241,13242,13243,13244,13245,13246,
8556013247,13248,13249,13250,13251,13252,13253,13254,13255,13256,13257,13258,
8556113259,13260,13261,13262,13263,13264,13265,13266,13267,13268,13269,13270,
8556213271,13272,13273,13274,13275,13276,13277,13278,13279,13280,13281,13282,
8556313283,13284,13285,13286,13287,13288,13289,13290,13291,13292,13293,13294,
8556413295,13296,13297,13298,13299,13300,13301,13302,13303,13304,13305,13306,
8556513307,13308,13309,13310,13311,13312,13313,13314,13315,13316,13317,13318,
8556613319,13320,13321,13322,13323,13324,13325,13326,13327,13328,13329,13330,
8556713331,13332,13333,13334,13335,13336,13337,13338,13339,13340,13341,13342,
8556813343,13344,13345,13346,13347,13348,13349,13350,13351,13352,13353,13354,
8556913355,13356,13357,13358,13359,13360,13361,13362,13363,13364,13365,13366,
8557013367,13368,13369,13370,13371,13372,13373,13374,13375,13376,13377,13378,
8557113379,13380,13381,13382,13383,13384,13385,13386,13387,13388,13389,13390,
8557213391,13392,13393,13394,13395,13396,13397,13398,13399,13400,13401,13402,
8557313403,13404,13405,13406,13407,13408,13409,13410,13411,13412,13413,13414,
8557413415,13416,13417,13418,13419,13420,13421,13422,13423,13424,13425,13426,
8557513427,13428,13429,13430,13431,13432,13433,13434,13435,13436,13437,13438,
8557613439,13440,13441,13442,13443,13444,13445,13446,13447,13448,13449,13450,
8557713451,13452,13453,13454,13455,13456,13457,13458,13459,13460,13461,13462,
8557813463,13464,13465,13466,13467,13468,13469,13470,13471,13472,13473,13474,
8557913475,13476,13477,13478,13479,13480,13481,13482,13483,13484,13485,13486,
8558013487,13488,13489,13490,13491,13492,13493,13494,13495,13496,13497,13498,
8558113499,13500,13501,13502,13503,13504,13505,13506,13507,13508,13509,13510,
8558213511,13512,13513,13514,13515,13516,13517,13518,13519,13520,13521,13522,
8558313523,13524,13525,13526,13527,13528,13529,13530,13531,13532,13533,13534,
8558413535,13536,13537,13538,13539,13540,13541,13542,13543,13544,13545,13546,
8558513547,13548,13549,13550,13551,13552,13553,13554,13555,13556,13557,13558,
8558613559,13560,13561,13562,13563,13564,13565,13566,13567,13568,13569,13570,
8558713571,13572,13573,13574,13575,13576,13577,13578,13579,13580,13581,13582,
8558813583,13584,13585,13586,13587,13588,13589,13590,13591,13592,13593,13594,
8558913595,13596,13597,13598,13599,13600,13601,13602,13603,13604,13605,13606,
8559013607,13608,13609,13610,13611,13612,13613,13614,13615,13616,13617,13618,
8559113619,13620,13621,13622,13623,13624,13625,13626,13627,13628,13629,13630,
8559213631,13632,13633,13634,13635,13636,13637,13638,13639,13640,13641,13642,
8559313643,13644,13645,13646,13647,13648,13649,13650,13651,13652,13653,13654,
8559413655,13656,13657,13658,13659,13660,13661,13662,13663,13664,13665,13666,
8559513667,13668,13669,13670,13671,13672,13673,13674,13675,13676,13677,13678,
8559613679,13680,13681,13682,13683,13684,13685,13686,13687,13688,13689,13690,
8559713691,13692,13693,13694,13695,13696,13697,13698,13699,13700,13701,13702,
8559813703,13704,13705,13706,13707,13708,13709,13710,13711,13712,13713,13714,
8559913715,13716,13717,13718,13719,13720,13721,13722,13723,13724,13725,13726,
8560013727,13728,13729,13730,13731,13732,13733,13734,13735,13736,13737,13738,
8560113739,13740,13741,13742,13743,13744,13745,13746,13747,13748,13749,13750,
8560213751,13752,13753,13754,13755,13756,13757,13758,13759,13760,13761,13762,
8560313763,13764,13765,13766,13767,13768,13769,13770,13771,13772,13773,13774,
8560413775,13776,13777,13778,13779,13780,13781,13782,13783,13784,13785,13786,
8560513787,13788,13789,13790,13791,13792,13793,13794,13795,13796,13797,13798,
8560613799,13800,13801,13802,13803,13804,13805,13806,13807,13808,13809,13810,
8560713811,13812,13813,13814,13815,13816,13817,13818,13819,13820,13821,13822,
8560813823,13824,13825,13826,13827,13828,13829,13830,13831,13832,13833,13834,
8560913835,13836,13837,13838,13839,13840,13841,13842,13843,13844,13845,13846,
8561013847,13848,13849,13850,13851,13852,13853,13854,13855,13856,13857,13858,
8561113859,13860,13861,13862,13863,13864,13865,13866,13867,13868,13869,13870,
8561213871,13872,13873,13874,13875,13876,13877,13878,13879,13880,13881,13882,
8561313883,13884,13885,13886,13887,13888,13889,13890,13891,13892,13893,13894,
8561413895,13896,13897,13898,13899,13900,13901,13902,13903,13904,13905,13906,
8561513907,13908,13909,13910,13911,13912,13913,13914,13915,13916,13917,13918,
8561613919,13920,13921,13922,13923,13924,13925,13926,13927,13928,13929,13930,
8561713931,13932,13933,13934,13935,13936,13937,13938,13939,13940,13941,13942,
8561813943,13944,13945,13946,13947,13948,13949,13950,13951,13952,13953,13954,
8561913955,13956,13957,13958,13959,13960,13961,13962,13963,13964,13965,13966,
8562013967,13968,13969,13970,13971,13972,13973,13974,13975,13976,13977,13978,
8562113979,13980,13981,13982,13983,13984,13985,13986,13987,13988,13989,13990,
8562213991,13992,13993,13994,13995,13996,13997,13998,13999,14000,14001,14002,
8562314003,14004,14005,14006,14007,14008,14009,14010,14011,14012,14013,14014,
8562414015,14016,14017,14018,14019,14020,14021,14022,14023,14024,14025,14026,
8562514027,14028,14029,14030,14031,14032,14033,14034,14035,14036,14037,14038,
8562614039,14040,14041,14042,14043,14044,14045,14046,14047,14048,14049,14050,
8562714051,14052,14053,14054,14055,14056,14057,14058,14059,14060,14061,14062,
8562814063,14064,14065,14066,14067,14068,14069,14070,14071,14072,14073,14074,
8562914075,14076,14077,14078,14079,14080,14081,14082,14083,14084,14085,14086,
8563014087,14088,14089,14090,14091,14092,14093,14094,14095,14096,14097,14098,
8563114099,14100,14101,14102,14103,14104,14105,14106,14107,14108,14109,14110,
8563214111,14112,14113,14114,14115,14116,14117,14118,14119,14120,14121,14122,
8563314123,14124,14125,14126,14127,14128,14129,14130,14131,14132,14133,14134,
8563414135,14136,14137,14138,14139,14140,14141,14142,14143,14144,14145,14146,
8563514147,14148,14149,14150,14151,14152,14153,14154,14155,14156,14157,14158,
8563614159,14160,14161,14162,14163,14164,14165,14166,14167,14168,14169,14170,
8563714171,14172,14173,14174,14175,14176,14177,14178,14179,14180,14181,14182,
8563814183,14184,14185,14186,14187,14188,14189,14190,14191,14192,14193,14194,
8563914195,14196,14197,14198,14199,14200,14201,14202,14203,14204,14205,14206,
8564014207,14208,14209,14210,14211,14212,14213,14214,14215,14216,14217,14218,
8564114219,14220,14221,14222,14223,14224,14225,14226,14227,14228,14229,14230,
8564214231,14232,14233,14234,14235,14236,14237,14238,14239,14240,14241,14242,
8564314243,14244,14245,14246,14247,14248,14249,14250,14251,14252,14253,14254,
8564414255,14256,14257,14258,14259,14260,14261,14262,14263,14264,14265,14266,
8564514267,14268,14269,14270,14271,14272,14273,14274,14275,14276,14277,14278,
8564614279,14280,14281,14282,14283,14284,14285,14286,14287,14288,14289,14290,
8564714291,14292,14293,14294,14295,14296,14297,14298,14299,14300,14301,14302,
8564814303,14304,14305,14306,14307,14308,14309,14310,14311,14312,14313,14314,
8564914315,14316,14317,14318,14319,14320,14321,14322,14323,14324,14325,14326,
8565014327,14328,14329,14330,14331,14332,14333,14334,14335,14336,14337,14338,
8565114339,14340,14341,14342,14343,14344,14345,14346,14347,14348,14349,14350,
8565214351,14352,14353,14354,14355,14356,14357,14358,14359,14360,14361,14362,
8565314363,14364,14365,14366,14367,14368,14369,14370,14371,14372,14373,14374,
8565414375,14376,14377,14378,14379,14380,14381,14382,14383,14384,14385,14386,
8565514387,14388,14389,14390,14391,14392,14393,14394,14395,14396,14397,14398,
8565614399,14400,14401,14402,14403,14404,14405,14406,14407,14408,14409,14410,
8565714411,14412,14413,14414,14415,14416,14417,14418,14419,14420,14421,14422,
8565814423,14424,14425,14426,14427,14428,14429,14430,14431,14432,14433,14434,
8565914435,14436,14437,14438,14439,14440,14441,14442,14443,14444,14445,14446,
8566014447,14448,14449,14450,14451,14452,14453,14454,14455,14456,14457,14458,
8566114459,14460,14461,14462,14463,14464,14465,14466,14467,14468,14469,14470,
8566214471,14472,14473,14474,14475,14476,14477,14478,14479,14480,14481,14482,
8566314483,14484,14485,14486,14487,14488,14489,14490,14491,14492,14493,14494,
8566414495,14496,14497,14498,14499,14500,14501,14502,14503,14504,14505,14506,
8566514507,14508,14509,14510,14511,14512,14513,14514,14515,14516,14517,14518,
8566614519,14520,14521,14522,14523,14524,14525,14526,14527,14528,14529,14530,
8566714531,14532,14533,14534,14535,14536,14537,14538,14539,14540,14541,14542,
8566814543,14544,14545,14546,14547,14548,14549,14550,14551,14552,14553,14554,
8566914555,14556,14557,14558,14559,14560,14561,14562,14563,14564,14565,14566,
8567014567,14568,14569,14570,14571,14572,14573,14574,14575,14576,14577,14578,
8567114579,14580,14581,14582,14583,14584,14585,14586,14587,14588,14589,14590,
8567214591,14592,14593,14594,14595,14596,14597,14598,14599,14600,14601,14602,
8567314603,14604,14605,14606,14607,14608,14609,14610,14611,14612,14613,14614,
8567414615,14616,14617,14618,14619,14620,14621,14622,14623,14624,14625,14626,
8567514627,14628,14629,14630,14631,14632,14633,14634,14635,14636,14637,14638,
8567614639,14640,14641,14642,14643,14644,14645,14646,14647,14648,14649,14650,
8567714651,14652,14653,14654,14655,14656,14657,14658,14659,14660,14661,14662,
8567814663,14664,14665,14666,14667,14668,14669,14670,14671,14672,14673,14674,
8567914675,14676,14677,14678,14679,14680,14681,14682,14683,14684,14685,14686,
8568014687,14688,14689,14690,14691,14692,14693,14694,14695,14696,14697,14698,
8568114699,14700,14701,14702,14703,14704,14705,14706,14707,14708,14709,14710,
8568214711,14712,14713,14714,14715,14716,14717,14718,14719,14720,14721,14722,
8568314723,14724,14725,14726,14727,14728,14729,14730,14731,14732,14733,14734,
8568414735,14736,14737,14738,14739,14740,14741,14742,14743,14744,14745,14746,
8568514747,14748,14749,14750,14751,14752,14753,14754,14755,14756,14757,14758,
8568614759,14760,14761,14762,14763,14764,14765,14766,14767,14768,14769,14770,
8568714771,14772,14773,14774,14775,14776,14777,14778,14779,14780,14781,14782,
8568814783,14784,14785,14786,14787,14788,14789,14790,14791,14792,14793,14794,
8568914795,14796,14797,14798,14799,14800,14801,14802,14803,14804,14805,14806,
8569014807,14808,14809,14810,14811,14812,14813,14814,14815,14816,14817,14818,
8569114819,14820,14821,14822,14823,14824,14825,14826,14827,14828,14829,14830,
8569214831,14832,14833,14834,14835,14836,14837,14838,14839,14840,14841,14842,
8569314843,14844,14845,14846,14847,14848,14849,14850,14851,14852,14853,14854,
8569414855,14856,14857,14858,14859,14860,14861,14862,14863,14864,14865,14866,
8569514867,14868,14869,14870,14871,14872,14873,14874,14875,14876,14877,14878,
8569614879,14880,14881,14882,14883,14884,14885,14886,14887,14888,14889,14890,
8569714891,14892,14893,14894,14895,14896,14897,14898,14899,14900,14901,14902,
8569814903,14904,14905,14906,14907,14908,14909,14910,14911,14912,14913,14914,
8569914915,14916,14917,14918,14919,14920,14921,14922,14923,14924,14925,14926,
8570014927,14928,14929,14930,14931,14932,14933,14934,14935,14936,14937,14938,
8570114939,14940,14941,14942,14943,14944,14945,14946,14947,14948,14949,14950,
8570214951,14952,14953,14954,14955,14956,14957,14958,14959,14960,14961,14962,
8570314963,14964,14965,14966,14967,14968,14969,14970,14971,14972,14973,14974,
8570414975,14976,14977,14978,14979,14980,14981,14982,14983,14984,14985,14986,
8570514987,14988,14989,14990,14991,14992,14993,14994,14995,14996,14997,14998,
8570614999,15000,15001,15002,15003,15004,15005,15006,15007,15008,15009,15010,
8570715011,15012,15013,15014,15015,15016,15017,15018,15019,15020,15021,15022,
8570815023,15024,15025,15026,15027,15028,15029,15030,15031,15032,15033,15034,
8570915035,15036,15037,15038,15039,15040,15041,15042,15043,15044,15045,15046,
8571015047,15048,15049,15050,15051,15052,15053,15054,15055,15056,15057,15058,
8571115059,15060,15061,15062,15063,15064,15065,15066,15067,15068,15069,15070,
8571215071,15072,15073,15074,15075,15076,15077,15078,15079,15080,15081,15082,
8571315083,15084,15085,15086,15087,15088,15089,15090,15091,15092,15093,15094,
8571415095,15096,15097,15098,15099,15100,15101,15102,15103,15104,15105,15106,
8571515107,15108,15109,15110,15111,15112,15113,15114,15115,15116,15117,15118,
8571615119,15120,15121,15122,15123,15124,15125,15126,15127,15128,15129,15130,
8571715131,15132,15133,15134,15135,15136,15137,15138,15139,15140,15141,15142,
8571815143,15144,15145,15146,15147,15148,15149,15150,15151,15152,15153,15154,
8571915155,15156,15157,15158,15159,15160,15161,15162,15163,15164,15165,15166,
8572015167,15168,15169,15170,15171,15172,15173,15174,15175,15176,15177,15178,
8572115179,15180,15181,15182,15183,15184,15185,15186,15187,15188,15189,15190,
8572215191,15192,15193,15194,15195,15196,15197,15198,15199,15200,15201,15202,
8572315203,15204,15205,15206,15207,15208,15209,15210,15211,15212,15213,15214,
8572415215,15216,15217,15218,15219,15220,15221,15222,15223,15224,15225,15226,
8572515227,15228,15229,15230,15231,15232,15233,15234,15235,15236,15237,15238,
8572615239,15240,15241,15242,15243,15244,15245,15246,15247,15248,15249,15250,
8572715251,15252,15253,15254,15255,15256,15257,15258,15259,15260,15261,15262,
8572815263,15264,15265,15266,15267,15268,15269,15270,15271,15272,15273,15274,
8572915275,15276,15277,15278,15279,15280,15281,15282,15283,15284,15285,15286,
8573015287,15288,15289,15290,15291,15292,15293,15294,15295,15296,15297,15298,
8573115299,15300,15301,15302,15303,15304,15305,15306,15307,15308,15309,15310,
8573215311,15312,15313,15314,15315,15316,15317,15318,15319,15320,15321,15322,
8573315323,15324,15325,15326,15327,15328,15329,15330,15331,15332,15333,15334,
8573415335,15336,15337,15338,15339,15340,15341,15342,15343,15344,15345,15346,
8573515347,15348,15349,15350,15351,15352,15353,15354,15355,15356,15357,15358,
8573615359,15360,15361,15362,15363,15364,15365,15366,15367,15368,15369,15370,
8573715371,15372,15373,15374,15375,15376,15377,15378,15379,15380,15381,15382,
8573815383,15384,15385,15386,15387,15388,15389,15390,15391,15392,15393,15394,
8573915395,15396,15397,15398,15399,15400,15401,15402,15403,15404,15405,15406,
8574015407,15408,15409,15410,15411,15412,15413,15414,15415,15416,15417,15418,
8574115419,15420,15421,15422,15423,15424,15425,15426,15427,15428,15429,15430,
8574215431,15432,15433,15434,15435,15436,15437,15438,15439,15440,15441,15442,
8574315443,15444,15445,15446,15447,15448,15449,15450,15451,15452,15453,15454,
8574415455,15456,15457,15458,15459,15460,15461,15462,15463,15464,15465,15466,
8574515467,15468,15469,15470,15471,15472,15473,15474,15475,15476,15477,15478,
8574615479,15480,15481,15482,15483,15484,15485,15486,15487,15488,15489,15490,
8574715491,15492,15493,15494,15495,15496,15497,15498,15499,15500,15501,15502,
8574815503,15504,15505,15506,15507,15508,15509,15510,15511,15512,15513,15514,
8574915515,15516,15517,15518,15519,15520,15521,15522,15523,15524,15525,15526,
8575015527,15528,15529,15530,15531,15532,15533,15534,15535,15536,15537,15538,
8575115539,15540,15541,15542,15543,15544,15545,15546,15547,15548,15549,15550,
8575215551,15552,15553,15554,15555,15556,15557,15558,15559,15560,15561,15562,
8575315563,15564,15565,15566,15567,15568,15569,15570,15571,15572,15573,15574,
8575415575,15576,15577,15578,15579,15580,15581,15582,15583,15584,15585,15586,
8575515587,15588,15589,15590,15591,15592,15593,15594,15595,15596,15597,15598,
8575615599,15600,15601,15602,15603,15604,15605,15606,15607,15608,15609,15610,
8575715611,15612,15613,15614,15615,15616,15617,15618,15619,15620,15621,15622,
8575815623,15624,15625,15626,15627,15628,15629,15630,15631,15632,15633,15634,
8575915635,15636,15637,15638,15639,15640,15641,15642,15643,15644,15645,15646,
8576015647,15648,15649,15650,15651,15652,15653,15654,15655,15656,15657,15658,
8576115659,15660,15661,15662,15663,15664,15665,15666,15667,15668,15669,15670,
8576215671,15672,15673,15674,15675,15676,15677,15678,15679,15680,15681,15682,
8576315683,15684,15685,15686,15687,15688,15689,15690,15691,15692,15693,15694,
8576415695,15696,15697,15698,15699,15700,15701,15702,15703,15704,15705,15706,
8576515707,15708,15709,15710,15711,15712,15713,15714,15715,15716,15717,15718,
8576615719,15720,15721,15722,15723,15724,15725,15726,15727,15728,15729,15730,
8576715731,15732,15733,15734,15735,15736,15737,15738,15739,15740,15741,15742,
8576815743,15744,15745,15746,15747,15748,15749,15750,15751,15752,15753,15754,
8576915755,15756,15757,15758,15759,15760,15761,15762,15763,15764,15765,15766,
8577015767,15768,15769,15770,15771,15772,15773,15774,15775,15776,15777,15778,
8577115779,15780,15781,15782,15783,15784,15785,15786,15787,15788,15789,15790,
8577215791,15792,15793,15794,15795,15796,15797,15798,15799,15800,15801,15802,
8577315803,15804,15805,15806,15807,15808,15809,15810,15811,15812,15813,15814,
8577415815,15816,15817,15818,15819,15820,15821,15822,15823,15824,15825,15826,
8577515827,15828,15829,15830,15831,15832,15833,15834,15835,15836,15837,15838,
8577615839,15840,15841,15842,15843,15844,15845,15846,15847,15848,15849,15850,
8577715851,15852,15853,15854,15855,15856,15857,15858,15859,15860,15861,15862,
8577815863,15864,15865,15866,15867,15868,15869,15870,15871,15872,15873,15874,
8577915875,15876,15877,15878,15879,15880,15881,15882,15883,15884,15885,15886,
8578015887,15888,15889,15890,15891,15892,15893,15894,15895,15896,15897,15898,
8578115899,15900,15901,15902,15903,15904,15905,15906,15907,15908,15909,15910,
8578215911,15912,15913,15914,15915,15916,15917,15918,15919,15920,15921,15922,
8578315923,15924,15925,15926,15927,15928,15929,15930,15931,15932,15933,15934,
8578415935,15936,15937,15938,15939,15940,15941,15942,15943,15944,15945,15946,
8578515947,15948,15949,15950,15951,15952,15953,15954,15955,15956,15957,15958,
8578615959,15960,15961,15962,15963,15964,15965,15966,15967,15968,15969,15970,
8578715971,15972,15973,15974,15975,15976,15977,15978,15979,15980,15981,15982,
8578815983,15984,15985,15986,15987,15988,15989,15990,15991,15992,15993,15994,
8578915995,15996,15997,15998,15999,16000,16001,16002,16003,16004,16005,16006,
8579016007,16008,16009,16010,16011,16012,16013,16014,16015,16016,16017,16018,
8579116019,16020,16021,16022,16023,16024,16025,16026,16027,16028,16029,16030,
8579216031,16032,16033,16034,16035,16036,16037,16038,16039,16040,16041,16042,
8579316043,16044,16045,16046,16047,16048,16049,16050,16051,16052,16053,16054,
8579416055,16056,16057,16058,16059,16060,16061,16062,16063,16064,16065,16066,
8579516067,16068,16069,16070,16071,16072,16073,16074,16075,16076,16077,16078,
8579616079,16080,16081,16082,16083,16084,16085,16086,16087,16088,16089,16090,
8579716091,16092,16093,16094,16095,16096,16097,16098,16099,16100,16101,16102,
8579816103,16104,16105,16106,16107,16108,16109,16110,16111,16112,16113,16114,
8579916115,16116,16117,16118,16119,16120,16121,16122,16123,16124,16125,16126,
8580016127,16128,16129,16130,16131,16132,16133,16134,16135,16136,16137,16138,
8580116139,16140,16141,16142,16143,16144,16145,16146,16147,16148,16149,16150,
8580216151,16152,16153,16154,16155,16156,16157,16158,16159,16160,16161,16162,
8580316163,16164,16165,16166,16167,16168,16169,16170,16171,16172,16173,16174,
8580416175,16176,16177,16178,16179,16180,16181,16182,16183,16184,16185,16186,
8580516187,16188,16189,16190,16191,16192,16193,16194,16195,16196,16197,16198,
8580616199,16200,16201,16202,16203,16204,16205,16206,16207,16208,16209,16210,
8580716211,16212,16213,16214,16215,16216,16217,16218,16219,16220,16221,16222,
8580816223,16224,16225,16226,16227,16228,16229,16230,16231,16232,16233,16234,
8580916235,16236,16237,16238,16239,16240,16241,16242,16243,16244,16245,16246,
8581016247,16248,16249,16250,16251,16252,16253,16254,16255,16256,16257,16258,
8581116259,16260,16261,16262,16263,16264,16265,16266,16267,16268,16269,16270,
8581216271,16272,16273,16274,16275,16276,16277,16278,16279,16280,16281,16282,
8581316283,16284,16285,16286,16287,16288,16289,16290,16291,16292,16293,16294,
8581416295,16296,16297,16298,16299,16300,16301,16302,16303,16304,16305,16306,
8581516307,16308,16309,16310,16311,16312,16313,16314,16315,16316,16317,16318,
8581616319,16320,16321,16322,16323,16324,16325,16326,16327,16328,16329,16330,
8581716331,16332,16333,16334,16335,16336,16337,16338,16339,16340,16341,16342,
8581816343,16344,16345,16346,16347,16348,16349,16350,16351,16352,16353,16354,
8581916355,16356,16357,16358,16359,16360,16361,16362,16363,16364,16365,16366,
8582016367,16368,16369,16370,16371,16372,16373,16374,16375,16376,16377,16378,
8582116379,16380,16381,16382,16383,16384,16385,16386,16387,16388,16389,16390,
8582216391,16392,16393,16394,16395,16396,16397,16398,16399,16400,16401,16402,
8582316403,16404,16405,16406,16407,16408,16409,16410,16411,16412,16413,16414,
8582416415,16416,16417,16418,16419,16420,16421,16422,16423,16424,16425,16426,
8582516427,16428,16429,16430,16431,16432,16433,16434,16435,16436,16437,16438,
8582616439,16440,16441,16442,16443,16444,16445,16446,16447,16448,16449,16450,
8582716451,16452,16453,16454,16455,16456,16457,16458,16459,16460,16461,16462,
8582816463,16464,16465,16466,16467,16468,16469,16470,16471,16472,16473,16474,
8582916475,16476,16477,16478,16479,16480,16481,16482,16483,16484,16485,16486,
8583016487,16488,16489,16490,16491,16492,16493,16494,16495,16496,16497,16498,
8583116499,16500,16501,16502,16503,16504,16505,16506,16507,16508,16509,16510,
8583216511,16512,16513,16514,16515,16516,16517,16518,16519,16520,16521,16522,
8583316523,16524,16525,16526,16527,16528,16529,16530,16531,16532,16533,16534,
8583416535,16536,16537,16538,16539,16540,16541,16542,16543,16544,16545,16546,
8583516547,16548,16549,16550,16551,16552,16553,16554,16555,16556,16557,16558,
8583616559,16560,16561,16562,16563,16564,16565,16566,16567,16568,16569,16570,
8583716571,16572,16573,16574,16575,16576,16577,16578,16579,16580,16581,16582,
8583816583,16584,16585,16586,16587,16588,16589,16590,16591,16592,16593,16594,
8583916595,16596,16597,16598,16599,16600,16601,16602,16603,16604,16605,16606,
8584016607,16608,16609,16610,16611,16612,16613,16614,16615,16616,16617,16618,
8584116619,16620,16621,16622,16623,16624,16625,16626,16627,16628,16629,16630,
8584216631,16632,16633,16634,16635,16636,16637,16638,16639,16640,16641,16642,
8584316643,16644,16645,16646,16647,16648,16649,16650,16651,16652,16653,16654,
8584416655,16656,16657,16658,16659,16660,16661,16662,16663,16664,16665,16666,
8584516667,16668,16669,16670,16671,16672,16673,16674,16675,16676,16677,16678,
8584616679,16680,16681,16682,16683,16684,16685,16686,16687,16688,16689,16690,
8584716691,16692,16693,16694,16695,16696,16697,16698,16699,16700,16701,16702,
8584816703,16704,16705,16706,16707,16708,16709,16710,16711,16712,16713,16714,
8584916715,16716,16717,16718,16719,16720,16721,16722,16723,16724,16725,16726,
8585016727,16728,16729,16730,16731,16732,16733,16734,16735,16736,16737,16738,
8585116739,16740,16741,16742,16743,16744,16745,16746,16747,16748,16749,16750,
8585216751,16752,16753,16754,16755,16756,16757,16758,16759,16760,16761,16762,
8585316763,16764,16765,16766,16767,16768,16769,16770,16771,16772,16773,16774,
8585416775,16776,16777,16778,16779,16780,16781,16782,16783,16784,16785,16786,
8585516787,16788,16789,16790,16791,16792,16793,16794,16795,16796,16797,16798,
8585616799,16800,16801,16802,16803,16804,16805,16806,16807,16808,16809,16810,
8585716811,16812,16813,16814,16815,16816,16817,16818,16819,16820,16821,16822,
8585816823,16824,16825,16826,16827,16828,16829,16830,16831,16832,16833,16834,
8585916835,16836,16837,16838,16839,16840,16841,16842,16843,16844,16845,16846,
8586016847,16848,16849,16850,16851,16852,16853,16854,16855,16856,16857,16858,
8586116859,16860,16861,16862,16863,16864,16865,16866,16867,16868,16869,16870,
8586216871,16872,16873,16874,16875,16876,16877,16878,16879,16880,16881,16882,
8586316883,16884,16885,16886,16887,16888,16889,16890,16891,16892,16893,16894,
8586416895,16896,16897,16898,16899,16900,16901,16902,16903,16904,16905,16906,
8586516907,16908,16909,16910,16911,16912,16913,16914,16915,16916,16917,16918,
8586616919,16920,16921,16922,16923,16924,16925,16926,16927,16928,16929,16930,
8586716931,16932,16933,16934,16935,16936,16937,16938,16939,16940,16941,16942,
8586816943,16944,16945,16946,16947,16948,16949,16950,16951,16952,16953,16954,
8586916955,16956,16957,16958,16959,16960,16961,16962,16963,16964,16965,16966,
8587016967,16968,16969,16970,16971,16972,16973,16974,16975,16976,16977,16978,
8587116979,16980,16981,16982,16983,16984,16985,16986,16987,16988,16989,16990,
8587216991,16992,16993,16994,16995,16996,16997,16998,16999,17000,17001,17002,
8587317003,17004,17005,17006,17007,17008,17009,17010,17011,17012,17013,17014,
8587417015,17016,17017,17018,17019,17020,17021,17022,17023,17024,17025,17026,
8587517027,17028,17029,17030,17031,17032,17033,17034,17035,17036,17037,17038,
8587617039,17040,17041,17042,17043,17044,17045,17046,17047,17048,17049,17050,
8587717051,17052,17053,17054,17055,17056,17057,17058,17059,17060,17061,17062,
8587817063,17064,17065,17066,17067,17068,17069,17070,17071,17072,17073,17074,
8587917075,17076,17077,17078,17079,17080,17081,17082,17083,17084,17085,17086,
8588017087,17088,17089,17090,17091,17092,17093,17094,17095,17096,17097,17098,
8588117099,17100,17101,17102,17103,17104,17105,17106,17107,17108,17109,17110,
8588217111,17112,17113,17114,17115,17116,17117,17118,17119,17120,17121,17122,
8588317123,17124,17125,17126,17127,17128,17129,17130,17131,17132,17133,17134,
8588417135,17136,17137,17138,17139,17140,17141,17142,17143,17144,17145,17146,
8588517147,17148,17149,17150,17151,17152,17153,17154,17155,17156,17157,17158,
8588617159,17160,17161,17162,17163,17164,17165,17166,17167,17168,17169,17170,
8588717171,17172,17173,17174,17175,17176,17177,17178,17179,17180,17181,17182,
8588817183,17184,17185,17186,17187,17188,17189,17190,17191,17192,17193,17194,
8588917195,17196,17197,17198,17199,17200,17201,17202,17203,17204,17205,17206,
8589017207,17208,17209,17210,17211,17212,17213,17214,17215,17216,17217,17218,
8589117219,17220,17221,17222,17223,17224,17225,17226,17227,17228,17229,17230,
8589217231,17232,17233,17234,17235,17236,17237,17238,17239,17240,17241,17242,
8589317243,17244,17245,17246,17247,17248,17249,17250,17251,17252,17253,17254,
8589417255,17256,17257,17258,17259,17260,17261,17262,17263,17264,17265,17266,
8589517267,17268,17269,17270,17271,17272,17273,17274,17275,17276,17277,17278,
8589617279,17280,17281,17282,17283,17284,17285,17286,17287,17288,17289,17290,
8589717291,17292,17293,17294,17295,17296,17297,17298,17299,17300,17301,17302,
8589817303,17304,17305,17306,17307,17308,17309,17310,17311,17312,17313,17314,
8589917315,17316,17317,17318,17319,17320,17321,17322,17323,17324,17325,17326,
8590017327,17328,17329,17330,17331,17332,17333,17334,17335,17336,17337,17338,
8590117339,17340,17341,17342,17343,17344,17345,17346,17347,17348,17349,17350,
8590217351,17352,17353,17354,17355,17356,17357,17358,17359,17360,17361,17362,
8590317363,17364,17365,17366,17367,17368,17369,17370,17371,17372,17373,17374,
8590417375,17376,17377,17378,17379,17380,17381,17382,17383,17384,17385,17386,
8590517387,17388,17389,17390,17391,17392,17393,17394,17395,17396,17397,17398,
8590617399,17400,17401,17402,17403,17404,17405,17406,17407,17408,17409,17410,
8590717411,17412,17413,17414,17415,17416,17417,17418,17419,17420,17421,17422,
8590817423,17424,17425,17426,17427,17428,17429,17430,17431,17432,17433,17434,
8590917435,17436,17437,17438,17439,17440,17441,17442,17443,17444,17445,17446,
8591017447,17448,17449,17450,17451,17452,17453,17454,17455,17456,17457,17458,
8591117459,17460,17461,17462,17463,17464,17465,17466,17467,17468,17469,17470,
8591217471,17472,17473,17474,17475,17476,17477,17478,17479,17480,17481,17482,
8591317483,17484,17485,17486,17487,17488,17489,17490,17491,17492,17493,17494,
8591417495,17496,17497,17498,17499,17500,17501,17502,17503,17504,17505,17506,
8591517507,17508,17509,17510,17511,17512,17513,17514,17515,17516,17517,17518,
8591617519,17520,17521,17522,17523,17524,17525,17526,17527,17528,17529,17530,
8591717531,17532,17533,17534,17535,17536,17537,17538,17539,17540,17541,17542,
8591817543,17544,17545,17546,17547,17548,17549,17550,17551,17552,17553,17554,
8591917555,17556,17557,17558,17559,17560,17561,17562,17563,17564,17565,17566,
8592017567,17568,17569,17570,17571,17572,17573,17574,17575,17576,17577,17578,
8592117579,17580,17581,17582,17583,17584,17585,17586,17587,17588,17589,17590,
8592217591,17592,17593,17594,17595,17596,17597,17598,17599,17600,17601,17602,
8592317603,17604,17605,17606,17607,17608,17609,17610,17611,17612,17613,17614,
8592417615,17616,17617,17618,17619,17620,17621,17622,17623,17624,17625,17626,
8592517627,17628,17629,17630,17631,17632,17633,17634,17635,17636,17637,17638,
8592617639,17640,17641,17642,17643,17644,17645,17646,17647,17648,17649,17650,
8592717651,17652,17653,17654,17655,17656,17657,17658,17659,17660,17661,17662,
8592817663,17664,17665,17666,17667,17668,17669,17670,17671,17672,17673,17674,
8592917675,17676,17677,17678,17679,17680,17681,17682,17683,17684,17685,17686,
8593017687,17688,17689,17690,17691,17692,17693,17694,17695,17696,17697,17698,
8593117699,17700,17701,17702,17703,17704,17705,17706,17707,17708,17709,17710,
8593217711,17712,17713,17714,17715,17716,17717,17718,17719,17720,17721,17722,
8593317723,17724,17725,17726,17727,17728,17729,17730,17731,17732,17733,17734,
8593417735,17736,17737,17738,17739,17740,17741,17742,17743,17744,17745,17746,
8593517747,17748,17749,17750,17751,17752,17753,17754,17755,17756,17757,17758,
8593617759,17760,17761,17762,17763,17764,17765,17766,17767,17768,17769,17770,
8593717771,17772,17773,17774,17775,17776,17777,17778,17779,17780,17781,17782,
8593817783,17784,17785,17786,17787,17788,17789,17790,17791,17792,17793,17794,
8593917795,17796,17797,17798,17799,17800,17801,17802,17803,17804,17805,17806,
8594017807,17808,17809,17810,17811,17812,17813,17814,17815,17816,17817,17818,
8594117819,17820,17821,17822,17823,17824,17825,17826,17827,17828,17829,17830,
8594217831,17832,17833,17834,17835,17836,17837,17838,17839,17840,17841,17842,
8594317843,17844,17845,17846,17847,17848,17849,17850,17851,17852,17853,17854,
8594417855,17856,17857,17858,17859,17860,17861,17862,17863,17864,17865,17866,
8594517867,17868,17869,17870,17871,17872,17873,17874,17875,17876,17877,17878,
8594617879,17880,17881,17882,17883,17884,17885,17886,17887,17888,17889,17890,
8594717891,17892,17893,17894,17895,17896,17897,17898,17899,17900,17901,17902,
8594817903,17904,17905,17906,17907,17908,17909,17910,17911,17912,17913,17914,
8594917915,17916,17917,17918,17919,17920,17921,17922,17923,17924,17925,17926,
8595017927,17928,17929,17930,17931,17932,17933,17934,17935,17936,17937,17938,
8595117939,17940,17941,17942,17943,17944,17945,17946,17947,17948,17949,17950,
8595217951,17952,17953,17954,17955,17956,17957,17958,17959,17960,17961,17962,
8595317963,17964,17965,17966,17967,17968,17969,17970,17971,17972,17973,17974,
8595417975,17976,17977,17978,17979,17980,17981,17982,17983,17984,17985,17986,
8595517987,17988,17989,17990,17991,17992,17993,17994,17995,17996,17997,17998,
8595617999,18000,18001,18002,18003,18004,18005,18006,18007,18008,18009,18010,
8595718011,18012,18013,18014,18015,18016,18017,18018,18019,18020,18021,18022,
8595818023,18024,18025,18026,18027,18028,18029,18030,18031,18032,18033,18034,
8595918035,18036,18037,18038,18039,18040,18041,18042,18043,18044,18045,18046,
8596018047,18048,18049,18050,18051,18052,18053,18054,18055,18056,18057,18058,
8596118059,18060,18061,18062,18063,18064,18065,18066,18067,18068,18069,18070,
8596218071,18072,18073,18074,18075,18076,18077,18078,18079,18080,18081,18082,
8596318083,18084,18085,18086,18087,18088,18089,18090,18091,18092,18093,18094,
8596418095,18096,18097,18098,18099,18100,18101,18102,18103,18104,18105,18106,
8596518107,18108,18109,18110,18111,18112,18113,18114,18115,18116,18117,18118,
8596618119,18120,18121,18122,18123,18124,18125,18126,18127,18128,18129,18130,
8596718131,18132,18133,18134,18135,18136,18137,18138,18139,18140,18141,18142,
8596818143,18144,18145,18146,18147,18148,18149,18150,18151,18152,18153,18154,
8596918155,18156,18157,18158,18159,18160,18161,18162,18163,18164,18165,18166,
8597018167,18168,18169,18170,18171,18172,18173,18174,18175,18176,18177,18178,
8597118179,18180,18181,18182,18183,18184,18185,18186,18187,18188,18189,18190,
8597218191,18192,18193,18194,18195,18196,18197,18198,18199,18200,18201,18202,
8597318203,18204,18205,18206,18207,18208,18209,18210,18211,18212,18213,18214,
8597418215,18216,18217,18218,18219,18220,18221,18222,18223,18224,18225,18226,
8597518227,18228,18229,18230,18231,18232,18233,18234,18235,18236,18237,18238,
8597618239,18240,18241,18242,18243,18244,18245,18246,18247,18248,18249,18250,
8597718251,18252,18253,18254,18255,18256,18257,18258,18259,18260,18261,18262,
8597818263,18264,18265,18266,18267,18268,18269,18270,18271,18272,18273,18274,
8597918275,18276,18277,18278,18279,18280,18281,18282,18283,18284,18285,18286,
8598018287,18288,18289,18290,18291,18292,18293,18294,18295,18296,18297,18298,
8598118299,18300,18301,18302,18303,18304,18305,18306,18307,18308,18309,18310,
8598218311,18312,18313,18314,18315,18316,18317,18318,18319,18320,18321,18322,
8598318323,18324,18325,18326,18327,18328,18329,18330,18331,18332,18333,18334,
8598418335,18336,18337,18338,18339,18340,18341,18342,18343,18344,18345,18346,
8598518347,18348,18349,18350,18351,18352,18353,18354,18355,18356,18357,18358,
8598618359,18360,18361,18362,18363,18364,18365,18366,18367,18368,18369,18370,
8598718371,18372,18373,18374,18375,18376,18377,18378,18379,18380,18381,18382,
8598818383,18384,18385,18386,18387,18388,18389,18390,18391,18392,18393,18394,
8598918395,18396,18397,18398,18399,18400,18401,18402,18403,18404,18405,18406,
8599018407,18408,18409,18410,18411,18412,18413,18414,18415,18416,18417,18418,
8599118419,18420,18421,18422,18423,18424,18425,18426,18427,18428,18429,18430,
8599218431,18432,18433,18434,18435,18436,18437,18438,18439,18440,18441,18442,
8599318443,18444,18445,18446,18447,18448,18449,18450,18451,18452,18453,18454,
8599418455,18456,18457,18458,18459,18460,18461,18462,18463,18464,18465,18466,
8599518467,18468,18469,18470,18471,18472,18473,18474,18475,18476,18477,18478,
8599618479,18480,18481,18482,18483,18484,18485,18486,18487,18488,18489,18490,
8599718491,18492,18493,18494,18495,18496,18497,18498,18499,18500,18501,18502,
8599818503,18504,18505,18506,18507,18508,18509,18510,18511,18512,18513,18514,
8599918515,18516,18517,18518,18519,18520,18521,18522,18523,18524,18525,18526,
8600018527,18528,18529,18530,18531,18532,18533,18534,18535,18536,18537,18538,
8600118539,18540,18541,18542,18543,18544,18545,18546,18547,18548,18549,18550,
8600218551,18552,18553,18554,18555,18556,18557,18558,18559,18560,18561,18562,
8600318563,18564,18565,18566,18567,18568,18569,18570,18571,18572,18573,18574,
8600418575,18576,18577,18578,18579,18580,18581,18582,18583,18584,18585,18586,
8600518587,18588,18589,18590,18591,18592,18593,18594,18595,18596,18597,18598,
8600618599,18600,18601,18602,18603,18604,18605,18606,18607,18608,18609,18610,
8600718611,18612,18613,18614,18615,18616,18617,18618,18619,18620,18621,18622,
8600818623,18624,18625,18626,18627,18628,18629,18630,18631,18632,18633,18634,
8600918635,18636,18637,18638,18639,18640,18641,18642,18643,18644,18645,18646,
8601018647,18648,18649,18650,18651,18652,18653,18654,18655,18656,18657,18658,
8601118659,18660,18661,18662,18663,18664,18665,18666,18667,18668,18669,18670,
8601218671,18672,18673,18674,18675,18676,18677,18678,18679,18680,18681,18682,
8601318683,18684,18685,18686,18687,18688,18689,18690,18691,18692,18693,18694,
8601418695,18696,18697,18698,18699,18700,18701,18702,18703,18704,18705,18706,
8601518707,18708,18709,18710,18711,18712,18713,18714,18715,18716,18717,18718,
8601618719,18720,18721,18722,18723,18724,18725,18726,18727,18728,18729,18730,
8601718731,18732,18733,18734,18735,18736,18737,18738,18739,18740,18741,18742,
8601818743,18744,18745,18746,18747,18748,18749,18750,18751,18752,18753,18754,
8601918755,18756,18757,18758,18759,18760,18761,18762,18763,18764,18765,18766,
8602018767,18768,18769,18770,18771,18772,18773,18774,18775,18776,18777,18778,
8602118779,18780,18781,18782,18783,18784,18785,18786,18787,18788,18789,18790,
8602218791,18792,18793,18794,18795,18796,18797,18798,18799,18800,18801,18802,
8602318803,18804,18805,18806,18807,18808,18809,18810,18811,18812,18813,18814,
8602418815,18816,18817,18818,18819,18820,18821,18822,18823,18824,18825,18826,
8602518827,18828,18829,18830,18831,18832,18833,18834,18835,18836,18837,18838,
8602618839,18840,18841,18842,18843,18844,18845,18846,18847,18848,18849,18850,
8602718851,18852,18853,18854,18855,18856,18857,18858,18859,18860,18861,18862,
8602818863,18864,18865,18866,18867,18868,18869,18870,18871,18872,18873,18874,
8602918875,18876,18877,18878,18879,18880,18881,18882,18883,18884,18885,18886,
8603018887,18888,18889,18890,18891,18892,18893,18894,18895,18896,18897,18898,
8603118899,18900,18901,18902,18903,18904,18905,18906,18907,18908,18909,18910,
8603218911,18912,18913,18914,18915,18916,18917,18918,18919,18920,18921,18922,
8603318923,18924,18925,18926,18927,18928,18929,18930,18931,18932,18933,18934,
8603418935,18936,18937,18938,18939,18940,18941,18942,18943,18944,18945,18946,
8603518947,18948,18949,18950,18951,18952,18953,18954,18955,18956,18957,18958,
8603618959,18960,18961,18962,18963,18964,18965,18966,18967,18968,18969,18970,
8603718971,18972,18973,18974,18975,18976,18977,18978,18979,18980,18981,18982,
8603818983,18984,18985,18986,18987,18988,18989,18990,18991,18992,18993,18994,
8603918995,18996,18997,18998,18999,19000,19001,19002,19003,19004,19005,19006,
8604019007,19008,19009,19010,19011,19012,19013,19014,19015,19016,19017,19018,
8604119019,19020,19021,19022,19023,19024,19025,19026,19027,19028,19029,19030,
8604219031,19032,19033,19034,19035,19036,19037,19038,19039,19040,19041,19042,
8604319043,19044,19045,19046,19047,19048,19049,19050,19051,19052,19053,19054,
8604419055,19056,19057,19058,19059,19060,19061,19062,19063,19064,19065,19066,
8604519067,19068,19069,19070,19071,19072,19073,19074,19075,19076,19077,19078,
8604619079,19080,19081,19082,19083,19084,19085,19086,19087,19088,19089,19090,
8604719091,19092,19093,19094,19095,19096,19097,19098,19099,19100,19101,19102,
8604819103,19104,19105,19106,19107,19108,19109,19110,19111,19112,19113,19114,
8604919115,19116,19117,19118,19119,19120,19121,19122,19123,19124,19125,19126,
8605019127,19128,19129,19130,19131,19132,19133,19134,19135,19136,19137,19138,
8605119139,19140,19141,19142,19143,19144,19145,19146,19147,19148,19149,19150,
8605219151,19152,19153,19154,19155,19156,19157,19158,19159,19160,19161,19162,
8605319163,19164,19165,19166,19167,19168,19169,19170,19171,19172,19173,19174,
8605419175,19176,19177,19178,19179,19180,19181,19182,19183,19184,19185,19186,
8605519187,19188,19189,19190,19191,19192,19193,19194,19195,19196,19197,19198,
8605619199,19200,19201,19202,19203,19204,19205,19206,19207,19208,19209,19210,
8605719211,19212,19213,19214,19215,19216,19217,19218,19219,19220,19221,19222,
8605819223,19224,19225,19226,19227,19228,19229,19230,19231,19232,19233,19234,
8605919235,19236,19237,19238,19239,19240,19241,19242,19243,19244,19245,19246,
8606019247,19248,19249,19250,19251,19252,19253,19254,19255,19256,19257,19258,
8606119259,19260,19261,19262,19263,19264,19265,19266,19267,19268,19269,19270,
8606219271,19272,19273,19274,19275,19276,19277,19278,19279,19280,19281,19282,
8606319283,19284,19285,19286,19287,19288,19289,19290,19291,19292,19293,19294,
8606419295,19296,19297,19298,19299,19300,19301,19302,19303,19304,19305,19306,
8606519307,19308,19309,19310,19311,19312,19313,19314,19315,19316,19317,19318,
8606619319,19320,19321,19322,19323,19324,19325,19326,19327,19328,19329,19330,
8606719331,19332,19333,19334,19335,19336,19337,19338,19339,19340,19341,19342,
8606819343,19344,19345,19346,19347,19348,19349,19350,19351,19352,19353,19354,
8606919355,19356,19357,19358,19359,19360,19361,19362,19363,19364,19365,19366,
8607019367,19368,19369,19370,19371,19372,19373,19374,19375,19376,19377,19378,
8607119379,19380,19381,19382,19383,19384,19385,19386,19387,19388,19389,19390,
8607219391,19392,19393,19394,19395,19396,19397,19398,19399,19400,19401,19402,
8607319403,19404,19405,19406,19407,19408,19409,19410,19411,19412,19413,19414,
8607419415,19416,19417,19418,19419,19420,19421,19422,19423,19424,19425,19426,
8607519427,19428,19429,19430,19431,19432,19433,19434,19435,19436,19437,19438,
8607619439,19440,19441,19442,19443,19444,19445,19446,19447,19448,19449,19450,
8607719451,19452,19453,19454,19455,19456,19457,19458,19459,19460,19461,19462,
8607819463,19464,19465,19466,19467,19468,19469,19470,19471,19472,19473,19474,
8607919475,19476,19477,19478,19479,19480,19481,19482,19483,19484,19485,19486,
8608019487,19488,19489,19490,19491,19492,19493,19494,19495,19496,19497,19498,
8608119499,19500,19501,19502,19503,19504,19505,19506,19507,19508,19509,19510,
8608219511,19512,19513,19514,19515,19516,19517,19518,19519,19520,19521,19522,
8608319523,19524,19525,19526,19527,19528,19529,19530,19531,19532,19533,19534,
8608419535,19536,19537,19538,19539,19540,19541,19542,19543,19544,19545,19546,
8608519547,19548,19549,19550,19551,19552,19553,19554,19555,19556,19557,19558,
8608619559,19560,19561,19562,19563,19564,19565,19566,19567,19568,19569,19570,
8608719571,19572,19573,19574,19575,19576,19577,19578,19579,19580,19581,19582,
8608819583,19584,19585,19586,19587,19588,19589,19590,19591,19592,19593,19594,
8608919595,19596,19597,19598,19599,19600,19601,19602,19603,19604,19605,19606,
8609019607,19608,19609,19610,19611,19612,19613,19614,19615,19616,19617,19618,
8609119619,19620,19621,19622,19623,19624,19625,19626,19627,19628,19629,19630,
8609219631,19632,19633,19634,19635,19636,19637,19638,19639,19640,19641,19642,
8609319643,19644,19645,19646,19647,19648,19649,19650,19651,19652,19653,19654,
8609419655,19656,19657,19658,19659,19660,19661,19662,19663,19664,19665,19666,
8609519667,19668,19669,19670,19671,19672,19673,19674,19675,19676,19677,19678,
8609619679,19680,19681,19682,19683,19684,19685,19686,19687,19688,19689,19690,
8609719691,19692,19693,19694,19695,19696,19697,19698,19699,19700,19701,19702,
8609819703,19704,19705,19706,19707,19708,19709,19710,19711,19712,19713,19714,
8609919715,19716,19717,19718,19719,19720,19721,19722,19723,19724,19725,19726,
8610019727,19728,19729,19730,19731,19732,19733,19734,19735,19736,19737,19738,
8610119739,19740,19741,19742,19743,19744,19745,19746,19747,19748,19749,19750,
8610219751,19752,19753,19754,19755,19756,19757,19758,19759,19760,19761,19762,
8610319763,19764,19765,19766,19767,19768,19769,19770,19771,19772,19773,19774,
8610419775,19776,19777,19778,19779,19780,19781,19782,19783,19784,19785,19786,
8610519787,19788,19789,19790,19791,19792,19793,19794,19795,19796,19797,19798,
8610619799,19800,19801,19802,19803,19804,19805,19806,19807,19808,19809,19810,
8610719811,19812,19813,19814,19815,19816,19817,19818,19819,19820,19821,19822,
8610819823,19824,19825,19826,19827,19828,19829,19830,19831,19832,19833,19834,
8610919835,19836,19837,19838,19839,19840,19841,19842,19843,19844,19845,19846,
8611019847,19848,19849,19850,19851,19852,19853,19854,19855,19856,19857,19858,
8611119859,19860,19861,19862,19863,19864,19865,19866,19867,19868,19869,19870,
8611219871,19872,19873,19874,19875,19876,19877,19878,19879,19880,19881,19882,
8611319883,19884,19885,19886,19887,19888,19889,19890,19891,19892,19893,19894,
8611419895,19896,19897,19898,19899,19900,19901,19902,19903,19904,19905,19906,
8611519907,19908,19909,19910,19911,19912,19913,19914,19915,19916,19917,19918,
8611619919,19920,19921,19922,19923,19924,19925,19926,19927,19928,19929,19930,
8611719931,19932,19933,19934,19935,19936,19937,19938,19939,19940,19941,19942,
8611819943,19944,19945,19946,19947,19948,19949,19950,19951,19952,19953,19954,
8611919955,19956,19957,19958,19959,19960,19961,19962,19963,19964,19965,19966,
8612019967,19968,19969,19970,19971,19972,19973,19974,19975,19976,19977,19978,
8612119979,19980,19981,19982,19983,19984,19985,19986,19987,19988,19989,19990,
8612219991,19992,19993,19994,19995,19996,19997,19998,19999,20000,20001,20002,
8612320003,20004,20005,20006,20007,20008,20009,20010,20011,20012,20013,20014,
8612420015,20016,20017,20018,20019,20020,20021,20022,20023,20024,20025,20026,
8612520027,20028,20029,20030,20031,20032,20033,20034,20035,20036,20037,20038,
8612620039,20040,20041,20042,20043,20044,20045,20046,20047,20048,20049,20050,
8612720051,20052,20053,20054,20055,20056,20057,20058,20059,20060,20061,20062,
8612820063,20064,20065,20066,20067,20068,20069,20070,20071,20072,20073,20074,
8612920075,20076,20077,20078,20079,20080,20081,20082,20083,20084,20085,20086,
8613020087,20088,20089,20090,20091,20092,20093,20094,20095,20096,20097,20098,
8613120099,20100,20101,20102,20103,20104,20105,20106,20107,20108,20109,20110,
8613220111,20112,20113,20114,20115,20116,20117,20118,20119,20120,20121,20122,
8613320123,20124,20125,20126,20127,20128,20129,20130,20131,20132,20133,20134,
8613420135,20136,20137,20138,20139,20140,20141,20142,20143,20144,20145,20146,
8613520147,20148,20149,20150,20151,20152,20153,20154,20155,20156,20157,20158,
8613620159,20160,20161,20162,20163,20164,20165,20166,20167,20168,20169,20170,
8613720171,20172,20173,20174,20175,20176,20177,20178,20179,20180,20181,20182,
8613820183,20184,20185,20186,20187,20188,20189,20190,20191,20192,20193,20194,
8613920195,20196,20197,20198,20199,20200,20201,20202,20203,20204,20205,20206,
8614020207,20208,20209,20210,20211,20212,20213,20214,20215,20216,20217,20218,
8614120219,20220,20221,20222,20223,20224,20225,20226,20227,20228,20229,20230,
8614220231,20232,20233,20234,20235,20236,20237,20238,20239,20240,20241,20242,
8614320243,20244,20245,20246,20247,20248,20249,20250,20251,20252,20253,20254,
8614420255,20256,20257,20258,20259,20260,20261,20262,20263,20264,20265,20266,
8614520267,20268,20269,20270,20271,20272,20273,20274,20275,20276,20277,20278,
8614620279,20280,20281,20282,20283,20284,20285,20286,20287,20288,20289,20290,
8614720291,20292,20293,20294,20295,20296,20297,20298,20299,20300,20301,20302,
8614820303,20304,20305,20306,20307,20308,20309,20310,20311,20312,20313,20314,
8614920315,20316,20317,20318,20319,20320,20321,20322,20323,20324,20325,20326,
8615020327,20328,20329,20330,20331,20332,20333,20334,20335,20336,20337,20338,
8615120339,20340,20341,20342,20343,20344,20345,20346,20347,20348,20349,20350,
8615220351,20352,20353,20354,20355,20356,20357,20358,20359,20360,20361,20362,
8615320363,20364,20365,20366,20367,20368,20369,20370,20371,20372,20373,20374,
8615420375,20376,20377,20378,20379,20380,20381,20382,20383,20384,20385,20386,
8615520387,20388,20389,20390,20391,20392,20393,20394,20395,20396,20397,20398,
8615620399,20400,20401,20402,20403,20404,20405,20406,20407,20408,20409,20410,
8615720411,20412,20413,20414,20415,20416,20417,20418,20419,20420,20421,20422,
8615820423,20424,20425,20426,20427,20428,20429,20430,20431,20432,20433,20434,
8615920435,20436,20437,20438,20439,20440,20441,20442,20443,20444,20445,20446,
8616020447,20448,20449,20450,20451,20452,20453,20454,20455,20456,20457,20458,
8616120459,20460,20461,20462,20463,20464,20465,20466,20467,20468,20469,20470,
8616220471,20472,20473,20474,20475,20476,20477,20478,20479,20480,20481,20482,
8616320483,20484,20485,20486,20487,20488,20489,20490,20491,20492,20493,20494,
8616420495,20496,20497,20498,20499,20500,20501,20502,20503,20504,20505,20506,
8616520507,20508,20509,20510,20511,20512,20513,20514,20515,20516,20517,20518,
8616620519,20520,20521,20522,20523,20524,20525,20526,20527,20528,20529,20530,
8616720531,20532,20533,20534,20535,20536,20537,20538,20539,20540,20541,20542,
8616820543,20544,20545,20546,20547,20548,20549,20550,20551,20552,20553,20554,
8616920555,20556,20557,20558,20559,20560,20561,20562,20563,20564,20565,20566,
8617020567,20568,20569,20570,20571,20572,20573,20574,20575,20576,20577,20578,
8617120579,20580,20581,20582,20583,20584,20585,20586,20587,20588,20589,20590,
8617220591,20592,20593,20594,20595,20596,20597,20598,20599,20600,20601,20602,
8617320603,20604,20605,20606,20607,20608,20609,20610,20611,20612,20613,20614,
8617420615,20616,20617,20618,20619,20620,20621,20622,20623,20624,20625,20626,
8617520627,20628,20629,20630,20631,20632,20633,20634,20635,20636,20637,20638,
8617620639,20640,20641,20642,20643,20644,20645,20646,20647,20648,20649,20650,
8617720651,20652,20653,20654,20655,20656,20657,20658,20659,20660,20661,20662,
8617820663,20664,20665,20666,20667,20668,20669,20670,20671,20672,20673,20674,
8617920675,20676,20677,20678,20679,20680,20681,20682,20683,20684,20685,20686,
8618020687,20688,20689,20690,20691,20692,20693,20694,20695,20696,20697,20698,
8618120699,20700,20701,20702,20703,20704,20705,20706,20707,20708,20709,20710,
8618220711,20712,20713,20714,20715,20716,20717,20718,20719,20720,20721,20722,
8618320723,20724,20725,20726,20727,20728,20729,20730,20731,20732,20733,20734,
8618420735,20736,20737,20738,20739,20740,20741,20742,20743,20744,20745,20746,
8618520747,20748,20749,20750,20751,20752,20753,20754,20755,20756,20757,20758,
8618620759,20760,20761,20762,20763,20764,20765,20766,20767,20768,20769,20770,
8618720771,20772,20773,20774,20775,20776,20777,20778,20779,20780,20781,20782,
8618820783,20784,20785,20786,20787,20788,20789,20790,20791,20792,20793,20794,
8618920795,20796,20797,20798,20799,20800,20801,20802,20803,20804,20805,20806,
8619020807,20808,20809,20810,20811,20812,20813,20814,20815,20816,20817,20818,
8619120819,20820,20821,20822,20823,20824,20825,20826,20827,20828,20829,20830,
8619220831,20832,20833,20834,20835,20836,20837,20838,20839,20840,20841,20842,
8619320843,20844,20845,20846,20847,20848,20849,20850,20851,20852,20853,20854,
8619420855,20856,20857,20858,20859,20860,20861,20862,20863,20864,20865,20866,
8619520867,20868,20869,20870,20871,20872,20873,20874,20875,20876,20877,20878,
8619620879,20880,20881,20882,20883,20884,20885,20886,20887,20888,20889,20890,
8619720891,20892,20893,20894,20895,20896,20897,20898,20899,20900,20901,20902,
8619820903,20904,20905,20906,20907,20908,20909,20910,20911,20912,20913,20914,
8619920915,20916,20917,20918,20919,20920,20921,20922,20923,20924,20925,20926,
8620020927,20928,20929,20930,20931,20932,20933,20934,20935,20936,20937,20938,
8620120939,20940,20941,20942,20943,20944,20945,20946,20947,20948,20949,20950,
8620220951,20952,20953,20954,20955,20956,20957,20958,20959,20960,20961,20962,
8620320963,20964,20965,20966,20967,20968,20969,20970,20971,20972,20973,20974,
8620420975,20976,20977,20978,20979,20980,20981,20982,20983,20984,20985,20986,
8620520987,20988,20989,20990,20991,20992,20993,20994,20995,20996,20997,20998,
8620620999,21000,21001,21002,21003,21004,21005,21006,21007,21008,21009,21010,
8620721011,21012,21013,21014,21015,21016,21017,21018,21019,21020,21021,21022,
8620821023,21024,21025,21026,21027,21028,21029,21030,21031,21032,21033,21034,
8620921035,21036,21037,21038,21039,21040,21041,21042,21043,21044,21045,21046,
8621021047,21048,21049,21050,21051,21052,21053,21054,21055,21056,21057,21058,
8621121059,21060,21061,21062,21063,21064,21065,21066,21067,21068,21069,21070,
8621221071,21072,21073,21074,21075,21076,21077,21078,21079,21080,21081,21082,
8621321083,21084,21085,21086,21087,21088,21089,21090,21091,21092,21093,21094,
8621421095,21096,21097,21098,21099,21100,21101,21102,21103,21104,21105,21106,
8621521107,21108,21109,21110,21111,21112,21113,21114,21115,21116,21117,21118,
8621621119,21120,21121,21122,21123,21124,21125,21126,21127,21128,21129,21130,
8621721131,21132,21133,21134,21135,21136,21137,21138,21139,21140,21141,21142,
8621821143,21144,21145,21146,21147,21148,21149,21150,21151,21152,21153,21154,
8621921155,21156,21157,21158,21159,21160,21161,21162,21163,21164,21165,21166,
8622021167,21168,21169,21170,21171,21172,21173,21174,21175,21176,21177,21178,
8622121179,21180,21181,21182,21183,21184,21185,21186,21187,21188,21189,21190,
8622221191,21192,21193,21194,21195,21196,21197,21198,21199,21200,21201,21202,
8622321203,21204,21205,21206,21207,21208,21209,21210,21211,21212,21213,21214,
8622421215,21216,21217,21218,21219,21220,21221,21222,21223,21224,21225,21226,
8622521227,21228,21229,21230,21231,21232,21233,21234,21235,21236,21237,21238,
8622621239,21240,21241,21242,21243,21244,21245,21246,21247,21248,21249,21250,
8622721251,21252,21253,21254,21255,21256,21257,21258,21259,21260,21261,21262,
8622821263,21264,21265,21266,21267,21268,21269,21270,21271,21272,21273,21274,
8622921275,21276,21277,21278,21279,21280,21281,21282,21283,21284,21285,21286,
8623021287,21288,21289,21290,21291,21292,21293,21294,21295,21296,21297,21298,
8623121299,21300,21301,21302,21303,21304,21305,21306,21307,21308,21309,21310,
8623221311,21312,21313,21314,21315,21316,21317,21318,21319,21320,21321,21322,
8623321323,21324,21325,21326,21327,21328,21329,21330,21331,21332,21333,21334,
8623421335,21336,21337,21338,21339,21340,21341,21342,21343,21344,21345,21346,
8623521347,21348,21349,21350,21351,21352,21353,21354,21355,21356,21357,21358,
8623621359,21360,21361,21362,21363,21364,21365,21366,21367,21368,21369,21370,
8623721371,21372,21373,21374,21375,21376,21377,21378,21379,21380,21381,21382,
8623821383,21384,21385,21386,21387,21388,21389,21390,21391,21392,21393,21394,
8623921395,21396,21397,21398,21399,21400,21401,21402,21403,21404,21405,21406,
8624021407,21408,21409,21410,21411,21412,21413,21414,21415,21416,21417,21418,
8624121419,21420,21421,21422,21423,21424,21425,21426,21427,21428,21429,21430,
8624221431,21432,21433,21434,21435,21436,21437,21438,21439,21440,21441,21442,
8624321443,21444,21445,21446,21447,21448,21449,21450,21451,21452,21453,21454,
8624421455,21456,21457,21458,21459,21460,21461,21462,21463,21464,21465,21466,
8624521467,21468,21469,21470,21471,21472,21473,21474,21475,21476,21477,21478,
8624621479,21480,21481,21482,21483,21484,21485,21486,21487,21488,21489,21490,
8624721491,21492,21493,21494,21495,21496,21497,21498,21499,21500,21501,21502,
8624821503,21504,21505,21506,21507,21508,21509,21510,21511,21512,21513,21514,
8624921515,21516,21517,21518,21519,21520,21521,21522,21523,21524,21525,21526,
8625021527,21528,21529,21530,21531,21532,21533,21534,21535,21536,21537,21538,
8625121539,21540,21541,21542,21543,21544,21545,21546,21547,21548,21549,21550,
8625221551,21552,21553,21554,21555,21556,21557,21558,21559,21560,21561,21562,
8625321563,21564,21565,21566,21567,21568,21569,21570,21571,21572,21573,21574,
8625421575,21576,21577,21578,21579,21580,21581,21582,21583,21584,21585,21586,
8625521587,21588,21589,21590,21591,21592,21593,21594,21595,21596,21597,21598,
8625621599,21600,21601,21602,21603,21604,21605,21606,21607,21608,21609,21610,
8625721611,21612,21613,21614,21615,21616,21617,21618,21619,21620,21621,21622,
8625821623,21624,21625,21626,21627,21628,21629,21630,21631,21632,21633,21634,
8625921635,21636,21637,21638,21639,21640,21641,21642,21643,21644,21645,21646,
8626021647,21648,21649,21650,21651,21652,21653,21654,21655,21656,21657,21658,
8626121659,21660,21661,21662,21663,21664,21665,21666,21667,21668,21669,21670,
8626221671,21672,21673,21674,21675,21676,21677,21678,21679,21680,21681,21682,
8626321683,21684,21685,21686,21687,21688,21689,21690,21691,21692,21693,21694,
8626421695,21696,21697,21698,21699,21700,21701,21702,21703,21704,21705,21706,
8626521707,21708,21709,21710,21711,21712,21713,21714,21715,21716,21717,21718,
8626621719,21720,21721,21722,21723,21724,21725,21726,21727,21728,21729,21730,
8626721731,21732,21733,21734,21735,21736,21737,21738,21739,21740,21741,21742,
8626821743,21744,21745,21746,21747,21748,21749,21750,21751,21752,21753,21754,
8626921755,21756,21757,21758,21759,21760,21761,21762,21763,21764,21765,21766,
8627021767,21768,21769,21770,21771,21772,21773,21774,21775,21776,21777,21778,
8627121779,21780,21781,21782,21783,21784,21785,21786,21787,21788,21789,21790,
8627221791,21792,21793,21794,21795,21796,21797,21798,21799,21800,21801,21802,
8627321803,21804,21805,21806,21807,21808,21809,21810,21811,21812,21813,21814,
8627421815,21816,21817,21818,21819,21820,21821,21822,21823,21824,21825,21826,
8627521827,21828,21829,21830,21831,21832,21833,21834,21835,21836,21837,21838,
8627621839,21840,21841,21842,21843,21844,21845,21846,21847,21848,21849,21850,
8627721851,21852,21853,21854,21855,21856,21857,21858,21859,21860,21861,21862,
8627821863,21864,21865,21866,21867,21868,21869,21870,21871,21872,21873,21874,
8627921875,21876,21877,21878,21879,21880,21881,21882,21883,21884,21885,21886,
8628021887,21888,21889,21890,21891,21892,21893,21894,21895,21896,21897,21898,
8628121899,21900,21901,21902,21903,21904,21905,21906,21907,21908,21909,21910,
8628221911,21912,21913,21914,21915,21916,21917,21918,21919,21920,21921,21922,
8628321923,21924,21925,21926,21927,21928,21929,21930,21931,21932,21933,21934,
8628421935,21936,21937,21938,21939,21940,21941,21942,21943,21944,21945,21946,
8628521947,21948,21949,21950,21951,21952,21953,21954,21955,21956,21957,21958,
8628621959,21960,21961,21962,21963,21964,21965,21966,21967,21968,21969,21970,
8628721971,21972,21973,21974,21975,21976,21977,21978,21979,21980,21981,21982,
8628821983,21984,21985,21986,21987,21988,21989,21990,21991,21992,21993,21994,
8628921995,21996,21997,21998,21999,22000,22001,22002,22003,22004,22005,22006,
8629022007,22008,22009,22010,22011,22012,22013,22014,22015,22016,22017,22018,
8629122019,22020,22021,22022,22023,22024,22025,22026,22027,22028,22029,22030,
8629222031,22032,22033,22034,22035,22036,22037,22038,22039,22040,22041,22042,
8629322043,22044,22045,22046,22047,22048,22049,22050,22051,22052,22053,22054,
8629422055,22056,22057,22058,22059,22060,22061,22062,22063,22064,22065,22066,
8629522067,22068,22069,22070,22071,22072,22073,22074,22075,22076,22077,22078,
8629622079,22080,22081,22082,22083,22084,22085,22086,22087,22088,22089,22090,
8629722091,22092,22093,22094,22095,22096,22097,22098,22099,22100,22101,22102,
8629822103,22104,22105,22106,22107,22108,22109,22110,22111,22112,22113,22114,
8629922115,22116,22117,22118,22119,22120,22121,22122,22123,22124,22125,22126,
8630022127,22128,22129,22130,22131,22132,22133,22134,22135,22136,22137,22138,
8630122139,22140,22141,22142,22143,22144,22145,22146,22147,22148,22149,22150,
8630222151,22152,22153,22154,22155,22156,22157,22158,22159,22160,22161,22162,
8630322163,22164,22165,22166,22167,22168,22169,22170,22171,22172,22173,22174,
8630422175,22176,22177,22178,22179,22180,22181,22182,22183,22184,22185,22186,
8630522187,22188,22189,22190,22191,22192,22193,22194,22195,22196,22197,22198,
8630622199,22200,22201,22202,22203,22204,22205,22206,22207,22208,22209,22210,
8630722211,22212,22213,22214,22215,22216,22217,22218,22219,22220,22221,22222,
8630822223,22224,22225,22226,22227,22228,22229,22230,22231,22232,22233,22234,
8630922235,22236,22237,22238,22239,22240,22241,22242,22243,22244,22245,22246,
8631022247,22248,22249,22250,22251,22252,22253,22254,22255,22256,22257,22258,
8631122259,22260,22261,22262,22263,22264,22265,22266,22267,22268,22269,22270,
8631222271,22272,22273,22274,22275,22276,22277,22278,22279,22280,22281,22282,
8631322283,22284,22285,22286,22287,22288,22289,22290,22291,22292,22293,22294,
8631422295,22296,22297,22298,22299,22300,22301,22302,22303,22304,22305,22306,
8631522307,22308,22309,22310,22311,22312,22313,22314,22315,22316,22317,22318,
8631622319,22320,22321,22322,22323,22324,22325,22326,22327,22328,22329,22330,
8631722331,22332,22333,22334,22335,22336,22337,22338,22339,22340,22341,22342,
8631822343,22344,22345,22346,22347,22348,22349,22350,22351,22352,22353,22354,
8631922355,22356,22357,22358,22359,22360,22361,22362,22363,22364,22365,22366,
8632022367,22368,22369,22370,22371,22372,22373,22374,22375,22376,22377,22378,
8632122379,22380,22381,22382,22383,22384,22385,22386,22387,22388,22389,22390,
8632222391,22392,22393,22394,22395,22396,22397,22398,22399,22400,22401,22402,
8632322403,22404,22405,22406,22407,22408,22409,22410,22411,22412,22413,22414,
8632422415,22416,22417,22418,22419,22420,22421,22422,22423,22424,22425,22426,
8632522427,22428,22429,22430,22431,22432,22433,22434,22435,22436,22437,22438,
8632622439,22440,22441,22442,22443,22444,22445,22446,22447,22448,22449,22450,
8632722451,22452,22453,22454,22455,22456,22457,22458,22459,22460,22461,22462,
8632822463,22464,22465,22466,22467,22468,22469,22470,22471,22472,22473,22474,
8632922475,22476,22477,22478,22479,22480,22481,22482,22483,22484,22485,22486,
8633022487,22488,22489,22490,22491,22492,22493,22494,22495,22496,22497,22498,
8633122499,22500,22501,22502,22503,22504,22505,22506,22507,22508,22509,22510,
8633222511,22512,22513,22514,22515,22516,22517,22518,22519,22520,22521,22522,
8633322523,22524,22525,22526,22527,22528,22529,22530,22531,22532,22533,22534,
8633422535,22536,22537,22538,22539,22540,22541,22542,22543,22544,22545,22546,
8633522547,22548,22549,22550,22551,22552,22553,22554,22555,22556,22557,22558,
8633622559,22560,22561,22562,22563,22564,22565,22566,22567,22568,22569,22570,
8633722571,22572,22573,22574,22575,22576,22577,22578,22579,22580,22581,22582,
8633822583,22584,22585,22586,22587,22588,22589,22590,22591,22592,22593,22594,
8633922595,22596,22597,22598,22599,22600,22601,22602,22603,22604,22605,22606,
8634022607,22608,22609,22610,22611,22612,22613,22614,22615,22616,22617,22618,
8634122619,22620,22621,22622,22623,22624,22625,22626,22627,22628,22629,22630,
8634222631,22632,22633,22634,22635,22636,22637,22638,22639,22640,22641,22642,
8634322643,22644,22645,22646,22647,22648,22649,22650,22651,22652,22653,22654,
8634422655,22656,22657,22658,22659,22660,22661,22662,22663,22664,22665,22666,
8634522667,22668,22669,22670,22671,22672,22673,22674,22675,22676,22677,22678,
8634622679,22680,22681,22682,22683,22684,22685,22686,22687,22688,22689,22690,
8634722691,22692,22693,22694,22695,22696,22697,22698,22699,22700,22701,22702,
8634822703,22704,22705,22706,22707,22708,22709,22710,22711,22712,22713,22714,
8634922715,22716,22717,22718,22719,22720,22721,22722,22723,22724,22725,22726,
8635022727,22728,22729,22730,22731,22732,22733,22734,22735,22736,22737,22738,
8635122739,22740,22741,22742,22743,22744,22745,22746,22747,22748,22749,22750,
8635222751,22752,22753,22754,22755,22756,22757,22758,22759,22760,22761,22762,
8635322763,22764,22765,22766,22767,22768,22769,22770,22771,22772,22773,22774,
8635422775,22776,22777,22778,22779,22780,22781,22782,22783,22784,22785,22786,
8635522787,22788,22789,22790,22791,22792,22793,22794,22795,22796,22797,22798,
8635622799,22800,22801,22802,22803,22804,22805,22806,22807,22808,22809,22810,
8635722811,22812,22813,22814,22815,22816,22817,22818,22819,22820,22821,22822,
8635822823,22824,22825,22826,22827,22828,22829,22830,22831,22832,22833,22834,
8635922835,22836,22837,22838,22839,22840,22841,22842,22843,22844,22845,22846,
8636022847,22848,22849,22850,22851,22852,22853,22854,22855,22856,22857,22858,
8636122859,22860,22861,22862,22863,22864,22865,22866,22867,22868,22869,22870,
8636222871,22872,22873,22874,22875,22876,22877,22878,22879,22880,22881,22882,
8636322883,22884,22885,22886,22887,22888,22889,22890,22891,22892,22893,22894,
8636422895,22896,22897,22898,22899,22900,22901,22902,22903,22904,22905,22906,
8636522907,22908,22909,22910,22911,22912,22913,22914,22915,22916,22917,22918,
8636622919,22920,22921,22922,22923,22924,22925,22926,22927,22928,22929,22930,
8636722931,22932,22933,22934,22935,22936,22937,22938,22939,22940,22941,22942,
8636822943,22944,22945,22946,22947,22948,22949,22950,22951,22952,22953,22954,
8636922955,22956,22957,22958,22959,22960,22961,22962,22963,22964,22965,22966,
8637022967,22968,22969,22970,22971,22972,22973,22974,22975,22976,22977,22978,
8637122979,22980,22981,22982,22983,22984,22985,22986,22987,22988,22989,22990,
8637222991,22992,22993,22994,22995,22996,22997,22998,22999,23000,23001,23002,
8637323003,23004,23005,23006,23007,23008,23009,23010,23011,23012,23013,23014,
8637423015,23016,23017,23018,23019,23020,23021,23022,23023,23024,23025,23026,
8637523027,23028,23029,23030,23031,23032,23033,23034,23035,23036,23037,23038,
8637623039,23040,23041,23042,23043,23044,23045,23046,23047,23048,23049,23050,
8637723051,23052,23053,23054,23055,23056,23057,23058,23059,23060,23061,23062,
8637823063,23064,23065,23066,23067,23068,23069,23070,23071,23072,23073,23074,
8637923075,23076,23077,23078,23079,23080,23081,23082,23083,23084,23085,23086,
8638023087,23088,23089,23090,23091,23092,23093,23094,23095,23096,23097,23098,
8638123099,23100,23101,23102,23103,23104,23105,23106,23107,23108,23109,23110,
8638223111,23112,23113,23114,23115,23116,23117,23118,23119,23120,23121,23122,
8638323123,23124,23125,23126,23127,23128,23129,23130,23131,23132,23133,23134,
8638423135,23136,23137,23138,23139,23140,23141,23142,23143,23144,23145,23146,
8638523147,23148,23149,23150,23151,23152,23153,23154,23155,23156,23157,23158,
8638623159,23160,23161,23162,23163,23164,23165,23166,23167,23168,23169,23170,
8638723171,23172,23173,23174,23175,23176,23177,23178,23179,23180,23181,23182,
8638823183,23184,23185,23186,23187,23188,23189,23190,23191,23192,23193,23194,
8638923195,23196,23197,23198,23199,23200,23201,23202,23203,23204,23205,23206,
8639023207,23208,23209,23210,23211,23212,23213,23214,23215,23216,23217,23218,
8639123219,23220,23221,23222,23223,23224,23225,23226,23227,23228,23229,23230,
8639223231,23232,23233,23234,23235,23236,23237,23238,23239,23240,23241,23242,
8639323243,23244,23245,23246,23247,23248,23249,23250,23251,23252,23253,23254,
8639423255,23256,23257,23258,23259,23260,23261,23262,23263,23264,23265,23266,
8639523267,23268,23269,23270,23271,23272,23273,23274,23275,23276,23277,23278,
8639623279,23280,23281,23282,23283,23284,23285,23286,23287,23288,23289,23290,
8639723291,23292,23293,23294,23295,23296,23297,23298,23299,23300,23301,23302,
8639823303,23304,23305,23306,23307,23308,23309,23310,23311,23312,23313,23314,
8639923315,23316,23317,23318,23319,23320,23321,23322,23323,23324,23325,23326,
8640023327,23328,23329,23330,23331,23332,23333,23334,23335,23336,23337,23338,
8640123339,23340,23341,23342,23343,23344,23345,23346,23347,23348,23349,23350,
8640223351,23352,23353,23354,23355,23356,23357,23358,23359,23360,23361,23362,
8640323363,23364,23365,23366,23367,23368,23369,23370,23371,23372,23373,23374,
8640423375,23376,23377,23378,23379,23380,23381,23382,23383,23384,23385,23386,
8640523387,23388,23389,23390,23391,23392,23393,23394,23395,23396,23397,23398,
8640623399,23400,23401,23402,23403,23404,23405,23406,23407,23408,23409,23410,
8640723411,23412,23413,23414,23415,23416,23417,23418,23419,23420,23421,23422,
8640823423,23424,23425,23426,23427,23428,23429,23430,23431,23432,23433,23434,
8640923435,23436,23437,23438,23439,23440,23441,23442,23443,23444,23445,23446,
8641023447,23448,23449,23450,23451,23452,23453,23454,23455,23456,23457,23458,
8641123459,23460,23461,23462,23463,23464,23465,23466,23467,23468,23469,23470,
8641223471,23472,23473,23474,23475,23476,23477,23478,23479,23480,23481,23482,
8641323483,23484,23485,23486,23487,23488,23489,23490,23491,23492,23493,23494,
8641423495,23496,23497,23498,23499,23500,23501,23502,23503,23504,23505,23506,
8641523507,23508,23509,23510,23511,23512,23513,23514,23515,23516,23517,23518,
8641623519,23520,23521,23522,23523,23524,23525,23526,23527,23528,23529,23530,
8641723531,23532,23533,23534,23535,23536,23537,23538,23539,23540,23541,23542,
8641823543,23544,23545,23546,23547,23548,23549,23550,23551,23552,23553,23554,
8641923555,23556,23557,23558,23559,23560,23561,23562,23563,23564,23565,23566,
8642023567,23568,23569,23570,23571,23572,23573,23574,23575,23576,23577,23578,
8642123579,23580,23581,23582,23583,23584,23585,23586,23587,23588,23589,23590,
8642223591,23592,23593,23594,23595,23596,23597,23598,23599,23600,23601,23602,
8642323603,23604,23605,23606,23607,23608,23609,23610,23611,23612,23613,23614,
8642423615,23616,23617,23618,23619,23620,23621,23622,23623,23624,23625,23626,
8642523627,23628,23629,23630,23631,23632,23633,23634,23635,23636,23637,23638,
8642623639,23640,23641,23642,23643,23644,23645,23646,23647,23648,23649,23650,
8642723651,23652,23653,23654,23655,23656,23657,23658,23659,23660,23661,23662,
8642823663,23664,23665,23666,23667,23668,23669,23670,23671,23672,23673,23674,
8642923675,23676,23677,23678,23679,23680,23681,23682,23683,23684,23685,23686,
8643023687,23688,23689,23690,23691,23692,23693,23694,23695,23696,23697,23698,
8643123699,23700,23701,23702,23703,23704,23705,23706,23707,23708,23709,23710,
8643223711,23712,23713,23714,23715,23716,23717,23718,23719,23720,23721,23722,
8643323723,23724,23725,23726,23727,23728,23729,23730,23731,23732,23733,23734,
8643423735,23736,23737,23738,23739,23740,23741,23742,23743,23744,23745,23746,
8643523747,23748,23749,23750,23751,23752,23753,23754,23755,23756,23757,23758,
8643623759,23760,23761,23762,23763,23764,23765,23766,23767,23768,23769,23770,
8643723771,23772,23773,23774,23775,23776,23777,23778,23779,23780,23781,23782,
8643823783,23784,23785,23786,23787,23788,23789,23790,23791,23792,23793,23794,
8643923795,23796,23797,23798,23799,23800,23801,23802,23803,23804,23805,23806,
8644023807,23808,23809,23810,23811,23812,23813,23814,23815,23816,23817,23818,
8644123819,23820,23821,23822,23823,23824,23825,23826,23827,23828,23829,23830,
8644223831,23832,23833,23834,23835,23836,23837,23838,23839,23840,23841,23842,
8644323843,23844,23845,23846,23847,23848,23849,23850,23851,23852,23853,23854,
8644423855,23856,23857,23858,23859,23860,23861,23862,23863,23864,23865,23866,
8644523867,23868,23869,23870,23871,23872,23873,23874,23875,23876,23877,23878,
8644623879,23880,23881,23882,23883,23884,23885,23886,23887,23888,23889,23890,
8644723891,23892,23893,23894,23895,23896,23897,23898,23899,23900,23901,23902,
8644823903,23904,23905,23906,23907,23908,23909,23910,23911,23912,23913,23914,
8644923915,23916,23917,23918,23919,23920,23921,23922,23923,23924,23925,23926,
8645023927,23928,23929,23930,23931,23932,23933,23934,23935,23936,23937,23938,
8645123939,23940,23941,23942,23943,23944,23945,23946,23947,23948,23949,23950,
8645223951,23952,23953,23954,23955,23956,23957,23958,23959,23960,23961,23962,
8645323963,23964,23965,23966,23967,23968,23969,23970,23971,23972,23973,23974,
8645423975,23976,23977,23978,23979,23980,23981,23982,23983,23984,23985,23986,
8645523987,23988,23989,23990,23991,23992,23993,23994,23995,23996,23997,23998,
8645623999,24000,24001,24002,24003,24004,24005,24006,24007,24008,24009,24010,
8645724011,24012,24013,24014,24015,24016,24017,24018,24019,24020,24021,24022,
8645824023,24024,24025,24026,24027,24028,24029,24030,24031,24032,24033,24034,
8645924035,24036,24037,24038,24039,24040,24041,24042,24043,24044,24045,24046,
8646024047,24048,24049,24050,24051,24052,24053,24054,24055,24056,24057,24058,
8646124059,24060,24061,24062,24063,24064,24065,24066,24067,24068,24069,24070,
8646224071,24072,24073,24074,24075,24076,24077,24078,24079,24080,24081,24082,
8646324083,24084,24085,24086,24087,24088,24089,24090,24091,24092,24093,24094,
8646424095,24096,24097,24098,24099,24100,24101,24102,24103,24104,24105,24106,
8646524107,24108,24109,24110,24111,24112,24113,24114,24115,24116,24117,24118,
8646624119,24120,24121,24122,24123,24124,24125,24126,24127,24128,24129,24130,
8646724131,24132,24133,24134,24135,24136,24137,24138,24139,24140,24141,24142,
8646824143,24144,24145,24146,24147,24148,24149,24150,24151,24152,24153,24154,
8646924155,24156,24157,24158,24159,24160,24161,24162,24163,24164,24165,24166,
8647024167,24168,24169,24170,24171,24172,24173,24174,24175,24176,24177,24178,
8647124179,24180,24181,24182,24183,24184,24185,24186,24187,24188,24189,24190,
8647224191,24192,24193,24194,24195,24196,24197,24198,24199,24200,24201,24202,
8647324203,24204,24205,24206,24207,24208,24209,24210,24211,24212,24213,24214,
8647424215,24216,24217,24218,24219,24220,24221,24222,24223,24224,24225,24226,
8647524227,24228,24229,24230,24231,24232,24233,24234,24235,24236,24237,24238,
8647624239,24240,24241,24242,24243,24244,24245,24246,24247,24248,24249,24250,
8647724251,24252,24253,24254,24255,24256,24257,24258,24259,24260,24261,24262,
8647824263,24264,24265,24266,24267,24268,24269,24270,24271,24272,24273,24274,
8647924275,24276,24277,24278,24279,24280,24281,24282,24283,24284,24285,24286,
8648024287,24288,24289,24290,24291,24292,24293,24294,24295,24296,24297,24298,
8648124299,24300,24301,24302,24303,24304,24305,24306,24307,24308,24309,24310,
8648224311,24312,24313,24314,24315,24316,24317,24318,24319,24320,24321,24322,
8648324323,24324,24325,24326,24327,24328,24329,24330,24331,24332,24333,24334,
8648424335,24336,24337,24338,24339,24340,24341,24342,24343,24344,24345,24346,
8648524347,24348,24349,24350,24351,24352,24353,24354,24355,24356,24357,24358,
8648624359,24360,24361,24362,24363,24364,24365,24366,24367,24368,24369,24370,
8648724371,24372,24373,24374,24375,24376,24377,24378,24379,24380,24381,24382,
8648824383,24384,24385,24386,24387,24388,24389,24390,24391,24392,24393,24394,
8648924395,24396,24397,24398,24399,24400,24401,24402,24403,24404,24405,24406,
8649024407,24408,24409,24410,24411,24412,24413,24414,24415,24416,24417,24418,
8649124419,24420,24421,24422,24423,24424,24425,24426,24427,24428,24429,24430,
8649224431,24432,24433,24434,24435,24436,24437,24438,24439,24440,24441,24442,
8649324443,24444,24445,24446,24447,24448,24449,24450,24451,24452,24453,24454,
8649424455,24456,24457,24458,24459,24460,24461,24462,24463,24464,24465,24466,
8649524467,24468,24469,24470,24471,24472,24473,24474,24475,24476,24477,24478,
8649624479,24480,24481,24482,24483,24484,24485,24486,24487,24488,24489,24490,
8649724491,24492,24493,24494,24495,24496,24497,24498,24499,24500,24501,24502,
8649824503,24504,24505,24506,24507,24508,24509,24510,24511,24512,24513,24514,
8649924515,24516,24517,24518,24519,24520,24521,24522,24523,24524,24525,24526,
8650024527,24528,24529,24530,24531,24532,24533,24534,24535,24536,24537,24538,
8650124539,24540,24541,24542,24543,24544,24545,24546,24547,24548,24549,24550,
8650224551,24552,24553,24554,24555,24556,24557,24558,24559,24560,24561,24562,
8650324563,24564,24565,24566,24567,24568,24569,24570,24571,24572,24573,24574,
8650424575,24576,24577,24578,24579,24580,24581,24582,24583,24584,24585,24586,
8650524587,24588,24589,24590,24591,24592,24593,24594,24595,24596,24597,24598,
8650624599,24600,24601,24602,24603,24604,24605,24606,24607,24608,24609,24610,
8650724611,24612,24613,24614,24615,24616,24617,24618,24619,24620,24621,24622,
8650824623,24624,24625,24626,24627,24628,24629,24630,24631,24632,24633,24634,
8650924635,24636,24637,24638,24639,24640,24641,24642,24643,24644,24645,24646,
8651024647,24648,24649,24650,24651,24652,24653,24654,24655,24656,24657,24658,
8651124659,24660,24661,24662,24663,24664,24665,24666,24667,24668,24669,24670,
8651224671,24672,24673,24674,24675,24676,24677,24678,24679,24680,24681,24682,
8651324683,24684,24685,24686,24687,24688,24689,24690,24691,24692,24693,24694,
8651424695,24696,24697,24698,24699,24700,24701,24702,24703,24704,24705,24706,
8651524707,24708,24709,24710,24711,24712,24713,24714,24715,24716,24717,24718,
8651624719,24720,24721,24722,24723,24724,24725,24726,24727,24728,24729,24730,
8651724731,24732,24733,24734,24735,24736,24737,24738,24739,24740,24741,24742,
8651824743,24744,24745,24746,24747,24748,24749,24750,24751,24752,24753,24754,
8651924755,24756,24757,24758,24759,24760,24761,24762,24763,24764,24765,24766,
8652024767,24768,24769,24770,24771,24772,24773,24774,24775,24776,24777,24778,
8652124779,24780,24781,24782,24783,24784,24785,24786,24787,24788,24789,24790,
8652224791,24792,24793,24794,24795,24796,24797,24798,24799,24800,24801,24802,
8652324803,24804,24805,24806,24807,24808,24809,24810,24811,24812,24813,24814,
8652424815,24816,24817,24818,24819,24820,24821,24822,24823,24824,24825,24826,
8652524827,24828,24829,24830,24831,24832,24833,24834,24835,24836,24837,24838,
8652624839,24840,24841,24842,24843,24844,24845,24846,24847,24848,24849,24850,
8652724851,24852,24853,24854,24855,24856,24857,24858,24859,24860,24861,24862,
8652824863,24864,24865,24866,24867,24868,24869,24870,24871,24872,24873,24874,
8652924875,24876,24877,24878,24879,24880,24881,24882,24883,24884,24885,24886,
8653024887,24888,24889,24890,24891,24892,24893,24894,24895,24896,24897,24898,
8653124899,24900,24901,24902,24903,24904,24905,24906,24907,24908,24909,24910,
8653224911,24912,24913,24914,24915,24916,24917,24918,24919,24920,24921,24922,
8653324923,24924,24925,24926,24927,24928,24929,24930,24931,24932,24933,24934,
8653424935,24936,24937,24938,24939,24940,24941,24942,24943,24944,24945,24946,
8653524947,24948,24949,24950,24951,24952,24953,24954,24955,24956,24957,24958,
8653624959,24960,24961,24962,24963,24964,24965,24966,24967,24968,24969,24970,
8653724971,24972,24973,24974,24975,24976,24977,24978,24979,24980,24981,24982,
8653824983,24984,24985,24986,24987,24988,24989,24990,24991,24992,24993,24994,
8653924995,24996,24997,24998,24999,25000,25001,25002,25003,25004,25005,25006,
8654025007,25008,25009,25010,25011,25012,25013,25014,25015,25016,25017,25018,
8654125019,25020,25021,25022,25023,25024,25025,25026,25027,25028,25029,25030,
8654225031,25032,25033,25034,25035,25036,25037,25038,25039,25040,25041,25042,
8654325043,25044,25045,25046,25047,25048,25049,25050,25051,25052,25053,25054,
8654425055,25056,25057,25058,25059,25060,25061,25062,25063,25064,25065,25066,
8654525067,25068,25069,25070,25071,25072,25073,25074,25075,25076,25077,25078,
8654625079,25080,25081,25082,25083,25084,25085,25086,25087,25088,25089,25090,
8654725091,25092,25093,25094,25095,25096,25097,25098,25099,25100,25101,25102,
8654825103,25104,25105,25106,25107,25108,25109,25110,25111,25112,25113,25114,
8654925115,25116,25117,25118,25119,25120,25121,25122,25123,25124,25125,25126,
8655025127,25128,25129,25130,25131,25132,25133,25134,25135,25136,25137,25138,
8655125139,25140,25141,25142,25143,25144,25145,25146,25147,25148,25149,25150,
8655225151,25152,25153,25154,25155,25156,25157,25158,25159,25160,25161,25162,
8655325163,25164,25165,25166,25167,25168,25169,25170,25171,25172,25173,25174,
8655425175,25176,25177,25178,25179,25180,25181,25182,25183,25184,25185,25186,
8655525187,25188,25189,25190,25191,25192,25193,25194,25195,25196,25197,25198,
8655625199,25200,25201,25202,25203,25204,25205,25206,25207,25208,25209,25210,
8655725211,25212,25213,25214,25215,25216,25217,25218,25219,25220,25221,25222,
8655825223,25224,25225,25226,25227,25228,25229,25230,25231,25232,25233,25234,
8655925235,25236,25237,25238,25239,25240,25241,25242,25243,25244,25245,25246,
8656025247,25248,25249,25250,25251,25252,25253,25254,25255,25256,25257,25258,
8656125259,25260,25261,25262,25263,25264,25265,25266,25267,25268,25269,25270,
8656225271,25272,25273,25274,25275,25276,25277,25278,25279,25280,25281,25282,
8656325283,25284,25285,25286,25287,25288,25289,25290,25291,25292,25293,25294,
8656425295,25296,25297,25298,25299,25300,25301,25302,25303,25304,25305,25306,
8656525307,25308,25309,25310,25311,25312,25313,25314,25315,25316,25317,25318,
8656625319,25320,25321,25322,25323,25324,25325,25326,25327,25328,25329,25330,
8656725331,25332,25333,25334,25335,25336,25337,25338,25339,25340,25341,25342,
8656825343,25344,25345,25346,25347,25348,25349,25350,25351,25352,25353,25354,
8656925355,25356,25357,25358,25359,25360,25361,25362,25363,25364,25365,25366,
8657025367,25368,25369,25370,25371,25372,25373,25374,25375,25376,25377,25378,
8657125379,25380,25381,25382,25383,25384,25385,25386,25387,25388,25389,25390,
8657225391,25392,25393,25394,25395,25396,25397,25398,25399,25400,25401,25402,
8657325403,25404,25405,25406,25407,25408,25409,25410,25411,25412,25413,25414,
8657425415,25416,25417,25418,25419,25420,25421,25422,25423,25424,25425,25426,
8657525427,25428,25429,25430,25431,25432,25433,25434,25435,25436,25437,25438,
8657625439,25440,25441,25442,25443,25444,25445,25446,25447,25448,25449,25450,
8657725451,25452,25453,25454,25455,25456,25457,25458,25459,25460,25461,25462,
8657825463,25464,25465,25466,25467,25468,25469,25470,25471,25472,25473,25474,
8657925475,25476,25477,25478,25479,25480,25481,25482,25483,25484,25485,25486,
8658025487,25488,25489,25490,25491,25492,25493,25494,25495,25496,25497,25498,
8658125499,25500,25501,25502,25503,25504,25505,25506,25507,25508,25509,25510,
8658225511,25512,25513,25514,25515,25516,25517,25518,25519,25520,25521,25522,
8658325523,25524,25525,25526,25527,25528,25529,25530,25531,25532,25533,25534,
8658425535,25536,25537,25538,25539,25540,25541,25542,25543,25544,25545,25546,
8658525547,25548,25549,25550,25551,25552,25553,25554,25555,25556,25557,25558,
8658625559,25560,25561,25562,25563,25564,25565,25566,25567,25568,25569,25570,
8658725571,25572,25573,25574,25575,25576,25577,25578,25579,25580,25581,25582,
8658825583,25584,25585,25586,25587,25588,25589,25590,25591,25592,25593,25594,
8658925595,25596,25597,25598,25599,25600,25601,25602,25603,25604,25605,25606,
8659025607,25608,25609,25610,25611,25612,25613,25614,25615,25616,25617,25618,
8659125619,25620,25621,25622,25623,25624,25625,25626,25627,25628,25629,25630,
8659225631,25632,25633,25634,25635,25636,25637,25638,25639,25640,25641,25642,
8659325643,25644,25645,25646,25647,25648,25649,25650,25651,25652,25653,25654,
8659425655,25656,25657,25658,25659,25660,25661,25662,25663,25664,25665,25666,
8659525667,25668,25669,25670,25671,25672,25673,25674,25675,25676,25677,25678,
8659625679,25680,25681,25682,25683,25684,25685,25686,25687,25688,25689,25690,
8659725691,25692,25693,25694,25695,25696,25697,25698,25699,25700,25701,25702,
8659825703,25704,25705,25706,25707,25708,25709,25710,25711,25712,25713,25714,
8659925715,25716,25717,25718,25719,25720,25721,25722,25723,25724,25725,25726,
8660025727,25728,25729,25730,25731,25732,25733,25734,25735,25736,25737,25738,
8660125739,25740,25741,25742,25743,25744,25745,25746,25747,25748,25749,25750,
8660225751,25752,25753,25754,25755,25756,25757,25758,25759,25760,25761,25762,
8660325763,25764,25765,25766,25767,25768,25769,25770,25771,25772,25773,25774,
8660425775,25776,25777,25778,25779,25780,25781,25782,25783,25784,25785,25786,
8660525787,25788,25789,25790,25791,25792,25793,25794,25795,25796,25797,25798,
8660625799,25800,25801,25802,25803,25804,25805,25806,25807,25808,25809,25810,
8660725811,25812,25813,25814,25815,25816,25817,25818,25819,25820,25821,25822,
8660825823,25824,25825,25826,25827,25828,25829,25830,25831,25832,25833,25834,
8660925835,25836,25837,25838,25839,25840,25841,25842,25843,25844,25845,25846,
8661025847,25848,25849,25850,25851,25852,25853,25854,25855,25856,25857,25858,
8661125859,25860,25861,25862,25863,25864,25865,25866,25867,25868,25869,25870,
8661225871,25872,25873,25874,25875,25876,25877,25878,25879,25880,25881,25882,
8661325883,25884,25885,25886,25887,25888,25889,25890,25891,25892,25893,25894,
8661425895,25896,25897,25898,25899,25900,25901,25902,25903,25904,25905,25906,
8661525907,25908,25909,25910,25911,25912,25913,25914,25915,25916,25917,25918,
8661625919,25920,25921,25922,25923,25924,25925,25926,25927,25928,25929,25930,
8661725931,25932,25933,25934,25935,25936,25937,25938,25939,25940,25941,25942,
8661825943,25944,25945,25946,25947,25948,25949,25950,25951,25952,25953,25954,
8661925955,25956,25957,25958,25959,25960,25961,25962,25963,25964,25965,25966,
8662025967,25968,25969,25970,25971,25972,25973,25974,25975,25976,25977,25978,
8662125979,25980,25981,25982,25983,25984,25985,25986,25987,25988,25989,25990,
8662225991,25992,25993,25994,25995,25996,25997,25998,25999,26000,26001,26002,
8662326003,26004,26005,26006,26007,26008,26009,26010,26011,26012,26013,26014,
8662426015,26016,26017,26018,26019,26020,26021,26022,26023,26024,26025,26026,
8662526027,26028,26029,26030,26031,26032,26033,26034,26035,26036,26037,26038,
8662626039,26040,26041,26042,26043,26044,26045,26046,26047,26048,26049,26050,
8662726051,26052,26053,26054,26055,26056,26057,26058,26059,26060,26061,26062,
8662826063,26064,26065,26066,26067,26068,26069,26070,26071,26072,26073,26074,
8662926075,26076,26077,26078,26079,26080,26081,26082,26083,26084,26085,26086,
8663026087,26088,26089,26090,26091,26092,26093,26094,26095,26096,26097,26098,
8663126099,26100,26101,26102,26103,26104,26105,26106,26107,26108,26109,26110,
8663226111,26112,26113,26114,26115,26116,26117,26118,26119,26120,26121,26122,
8663326123,26124,26125,26126,26127,26128,26129,26130,26131,26132,26133,26134,
8663426135,26136,26137,26138,26139,26140,26141,26142,26143,26144,26145,26146,
8663526147,26148,26149,26150,26151,26152,26153,26154,26155,26156,26157,26158,
8663626159,26160,26161,26162,26163,26164,26165,26166,26167,26168,26169,26170,
8663726171,26172,26173,26174,26175,26176,26177,26178,26179,26180,26181,26182,
8663826183,26184,26185,26186,26187,26188,26189,26190,26191,26192,26193,26194,
8663926195,26196,26197,26198,26199,26200,26201,26202,26203,26204,26205,26206,
8664026207,26208,26209,26210,26211,26212,26213,26214,26215,26216,26217,26218,
8664126219,26220,26221,26222,26223,26224,26225,26226,26227,26228,26229,26230,
8664226231,26232,26233,26234,26235,26236,26237,26238,26239,26240,26241,26242,
8664326243,26244,26245,26246,26247,26248,26249,26250,26251,26252,26253,26254,
8664426255,26256,26257,26258,26259,26260,26261,26262,26263,26264,26265,26266,
8664526267,26268,26269,26270,26271,26272,26273,26274,26275,26276,26277,26278,
8664626279,26280,26281,26282,26283,26284,26285,26286,26287,26288,26289,26290,
8664726291,26292,26293,26294,26295,26296,26297,26298,26299,26300,26301,26302,
8664826303,26304,26305,26306,26307,26308,26309,26310,26311,26312,26313,26314,
8664926315,26316,26317,26318,26319,26320,26321,26322,26323,26324,26325,26326,
8665026327,26328,26329,26330,26331,26332,26333,26334,26335,26336,26337,26338,
8665126339,26340,26341,26342,26343,26344,26345,26346,26347,26348,26349,26350,
8665226351,26352,26353,26354,26355,26356,26357,26358,26359,26360,26361,26362,
8665326363,26364,26365,26366,26367,26368,26369,26370,26371,26372,26373,26374,
8665426375,26376,26377,26378,26379,26380,26381,26382,26383,26384,26385,26386,
8665526387,26388,26389,26390,26391,26392,26393,26394,26395,26396,26397,26398,
8665626399,26400,26401,26402,26403,26404,26405,26406,26407,26408,26409,26410,
8665726411,26412,26413,26414,26415,26416,26417,26418,26419,26420,26421,26422,
8665826423,26424,26425,26426,26427,26428,26429,26430,26431,26432,26433,26434,
8665926435,26436,26437,26438,26439,26440,26441,26442,26443,26444,26445,26446,
8666026447,26448,26449,26450,26451,26452,26453,26454,26455,26456,26457,26458,
8666126459,26460,26461,26462,26463,26464,26465,26466,26467,26468,26469,26470,
8666226471,26472,26473,26474,26475,26476,26477,26478,26479,26480,26481,26482,
8666326483,26484,26485,26486,26487,26488,26489,26490,26491,26492,26493,26494,
8666426495,26496,26497,26498,26499,26500,26501,26502,26503,26504,26505,26506,
8666526507,26508,26509,26510,26511,26512,26513,26514,26515,26516,26517,26518,
8666626519,26520,26521,26522,26523,26524,26525,26526,26527,26528,26529,26530,
8666726531,26532,26533,26534,26535,26536,26537,26538,26539,26540,26541,26542,
8666826543,26544,26545,26546,26547,26548,26549,26550,26551,26552,26553,26554,
8666926555,26556,26557,26558,26559,26560,26561,26562,26563,26564,26565,26566,
8667026567,26568,26569,26570,26571,26572,26573,26574,26575,26576,26577,26578,
8667126579,26580,26581,26582,26583,26584,26585,26586,26587,26588,26589,26590,
8667226591,26592,26593,26594,26595,26596,26597,26598,26599,26600,26601,26602,
8667326603,26604,26605,26606,26607,26608,26609,26610,26611,26612,26613,26614,
8667426615,26616,26617,26618,26619,26620,26621,26622,26623,26624,26625,26626,
8667526627,26628,26629,26630,26631,26632,26633,26634,26635,26636,26637,26638,
8667626639,26640,26641,26642,26643,26644,26645,26646,26647,26648,26649,26650,
8667726651,26652,26653,26654,26655,26656,26657,26658,26659,26660,26661,26662,
8667826663,26664,26665,26666,26667,26668,26669,26670,26671,26672,26673,26674,
8667926675,26676,26677,26678,26679,26680,26681,26682,26683,26684,26685,26686,
8668026687,26688,26689,26690,26691,26692,26693,26694,26695,26696,26697,26698,
8668126699,26700,26701,26702,26703,26704,26705,26706,26707,26708,26709,26710,
8668226711,26712,26713,26714,26715,26716,26717,26718,26719,26720,26721,26722,
8668326723,26724,26725,26726,26727,26728,26729,26730,26731,26732,26733,26734,
8668426735,26736,26737,26738,26739,26740,26741,26742,26743,26744,26745,26746,
8668526747,26748,26749,26750,26751,26752,26753,26754,26755,26756,26757,26758,
8668626759,26760,26761,26762,26763,26764,26765,26766,26767,26768,26769,26770,
8668726771,26772,26773,26774,26775,26776,26777,26778,26779,26780,26781,26782,
8668826783,26784,26785,26786,26787,26788,26789,26790,26791,26792,26793,26794,
8668926795,26796,26797,26798,26799,26800,26801,26802,26803,26804,26805,26806,
8669026807,26808,26809,26810,26811,26812,26813,26814,26815,26816,26817,26818,
8669126819,26820,26821,26822,26823,26824,26825,26826,26827,26828,26829,26830,
8669226831,26832,26833,26834,26835,26836,26837,26838,26839,26840,26841,26842,
8669326843,26844,26845,26846,26847,26848,26849,26850,26851,26852,26853,26854,
8669426855,26856,26857,26858,26859,26860,26861,26862,26863,26864,26865,26866,
8669526867,26868,26869,26870,26871,26872,26873,26874,26875,26876,26877,26878,
8669626879,26880,26881,26882,26883,26884,26885,26886,26887,26888,26889,26890,
8669726891,26892,26893,26894,26895,26896,26897,26898,26899,26900,26901,26902,
8669826903,26904,26905,26906,26907,26908,26909,26910,26911,26912,26913,26914,
8669926915,26916,26917,26918,26919,26920,26921,26922,26923,26924,26925,26926,
8670026927,26928,26929,26930,26931,26932,26933,26934,26935,26936,26937,26938,
8670126939,26940,26941,26942,26943,26944,26945,26946,26947,26948,26949,26950,
8670226951,26952,26953,26954,26955,26956,26957,26958,26959,26960,26961,26962,
8670326963,26964,26965,26966,26967,26968,26969,26970,26971,26972,26973,26974,
8670426975,26976,26977,26978,26979,26980,26981,26982,26983,26984,26985,26986,
8670526987,26988,26989,26990,26991,26992,26993,26994,26995,26996,26997,26998,
8670626999,27000,27001,27002,27003,27004,27005,27006,27007,27008,27009,27010,
8670727011,27012,27013,27014,27015,27016,27017,27018,27019,27020,27021,27022,
8670827023,27024,27025,27026,27027,27028,27029,27030,27031,27032,27033,27034,
8670927035,27036,27037,27038,27039,27040,27041,27042,27043,27044,27045,27046,
8671027047,27048,27049,27050,27051,27052,27053,27054,27055,27056,27057,27058,
8671127059,27060,27061,27062,27063,27064,27065,27066,27067,27068,27069,27070,
8671227071,27072,27073,27074,27075,27076,27077,27078,27079,27080,27081,27082,
8671327083,27084,27085,27086,27087,27088,27089,27090,27091,27092,27093,27094,
8671427095,27096,27097,27098,27099,27100,27101,27102,27103,27104,27105,27106,
8671527107,27108,27109,27110,27111,27112,27113,27114,27115,27116,27117,27118,
8671627119,27120,27121,27122,27123,27124,27125,27126,27127,27128,27129,27130,
8671727131,27132,27133,27134,27135,27136,27137,27138,27139,27140,27141,27142,
8671827143,27144,27145,27146,27147,27148,27149,27150,27151,27152,27153,27154,
8671927155,27156,27157,27158,27159,27160,27161,27162,27163,27164,27165,27166,
8672027167,27168,27169,27170,27171,27172,27173,27174,27175,27176,27177,27178,
8672127179,27180,27181,27182,27183,27184,27185,27186,27187,27188,27189,27190,
8672227191,27192,27193,27194,27195,27196,27197,27198,27199,27200,27201,27202,
8672327203,27204,27205,27206,27207,27208,27209,27210,27211,27212,27213,27214,
8672427215,27216,27217,27218,27219,27220,27221,27222,27223,27224,27225,27226,
8672527227,27228,27229,27230,27231,27232,27233,27234,27235,27236,27237,27238,
8672627239,27240,27241,27242,27243,27244,27245,27246,27247,27248,27249,27250,
8672727251,27252,27253,27254,27255,27256,27257,27258,27259,27260,27261,27262,
8672827263,27264,27265,27266,27267,27268,27269,27270,27271,27272,27273,27274,
8672927275,27276,27277,27278,27279,27280,27281,27282,27283,27284,27285,27286,
8673027287,27288,27289,27290,27291,27292,27293,27294,27295,27296,27297,27298,
8673127299,27300,27301,27302,27303,27304,27305,27306,27307,27308,27309,27310,
8673227311,27312,27313,27314,27315,27316,27317,27318,27319,27320,27321,27322,
8673327323,27324,27325,27326,27327,27328,27329,27330,27331,27332,27333,27334,
8673427335,27336,27337,27338,27339,27340,27341,27342,27343,27344,27345,27346,
8673527347,27348,27349,27350,27351,27352,27353,27354,27355,27356,27357,27358,
8673627359,27360,27361,27362,27363,27364,27365,27366,27367,27368,27369,27370,
8673727371,27372,27373,27374,27375,27376,27377,27378,27379,27380,27381,27382,
8673827383,27384,27385,27386,27387,27388,27389,27390,27391,27392,27393,27394,
8673927395,27396,27397,27398,27399,27400,27401,27402,27403,27404,27405,27406,
8674027407,27408,27409,27410,27411,27412,27413,27414,27415,27416,27417,27418,
8674127419,27420,27421,27422,27423,27424,27425,27426,27427,27428,27429,27430,
8674227431,27432,27433,27434,27435,27436,27437,27438,27439,27440,27441,27442,
8674327443,27444,27445,27446,27447,27448,27449,27450,27451,27452,27453,27454,
8674427455,27456,27457,27458,27459,27460,27461,27462,27463,27464,27465,27466,
8674527467,27468,27469,27470,27471,27472,27473,27474,27475,27476,27477,27478,
8674627479,27480,27481,27482,27483,27484,27485,27486,27487,27488,27489,27490,
8674727491,27492,27493,27494,27495,27496,27497,27498,27499,27500,27501,27502,
8674827503,27504,27505,27506,27507,27508,27509,27510,27511,27512,27513,27514,
8674927515,27516,27517,27518,27519,27520,27521,27522,27523,27524,27525,27526,
8675027527,27528,27529,27530,27531,27532,27533,27534,27535,27536,27537,27538,
8675127539,27540,27541,27542,27543,27544,27545,27546,27547,27548,27549,27550,
8675227551,27552,27553,27554,27555,27556,27557,27558,27559,27560,27561,27562,
8675327563,27564,27565,27566,27567,27568,27569,27570,27571,27572,27573,27574,
8675427575,27576,27577,27578,27579,27580,27581,27582,27583,27584,27585,27586,
8675527587,27588,27589,27590,27591,27592,27593,27594,27595,27596,27597,27598,
8675627599,27600,27601,27602,27603,27604,27605,27606,27607,27608,27609,27610,
8675727611,27612,27613,27614,27615,27616,27617,27618,27619,27620,27621,27622,
8675827623,27624,27625,27626,27627,27628,27629,27630,27631,27632,27633,27634,
8675927635,27636,27637,27638,27639,27640,27641,27642,27643,27644,27645,27646,
8676027647,27648,27649,27650,27651,27652,27653,27654,27655,27656,27657,27658,
8676127659,27660,27661,27662,27663,27664,27665,27666,27667,27668,27669,27670,
8676227671,27672,27673,27674,27675,27676,27677,27678,27679,27680,27681,27682,
8676327683,27684,27685,27686,27687,27688,27689,27690,27691,27692,27693,27694,
8676427695,27696,27697,27698,27699,27700,27701,27702,27703,27704,27705,27706,
8676527707,27708,27709,27710,27711,27712,27713,27714,27715,27716,27717,27718,
8676627719,27720,27721,27722,27723,27724,27725,27726,27727,27728,27729,27730,
8676727731,27732,27733,27734,27735,27736,27737,27738,27739,27740,27741,27742,
8676827743,27744,27745,27746,27747,27748,27749,27750,27751,27752,27753,27754,
8676927755,27756,27757,27758,27759,27760,27761,27762,27763,27764,27765,27766,
8677027767,27768,27769,27770,27771,27772,27773,27774,27775,27776,27777,27778,
8677127779,27780,27781,27782,27783,27784,27785,27786,27787,27788,27789,27790,
8677227791,27792,27793,27794,27795,27796,27797,27798,27799,27800,27801,27802,
8677327803,27804,27805,27806,27807,27808,27809,27810,27811,27812,27813,27814,
8677427815,27816,27817,27818,27819,27820,27821,27822,27823,27824,27825,27826,
8677527827,27828,27829,27830,27831,27832,27833,27834,27835,27836,27837,27838,
8677627839,27840,27841,27842,27843,27844,27845,27846,27847,27848,27849,27850,
8677727851,27852,27853,27854,27855,27856,27857,27858,27859,27860,27861,27862,
8677827863,27864,27865,27866,27867,27868,27869,27870,27871,27872,27873,27874,
8677927875,27876,27877,27878,27879,27880,27881,27882,27883,27884,27885,27886,
8678027887,27888,27889,27890,27891,27892,27893,27894,27895,27896,27897,27898,
8678127899,27900,27901,27902,27903,27904,27905,27906,27907,27908,27909,27910,
8678227911,27912,27913,27914,27915,27916,27917,27918,27919,27920,27921,27922,
8678327923,27924,27925,27926,27927,27928,27929,27930,27931,27932,27933,27934,
8678427935,27936,27937,27938,27939,27940,27941,27942,27943,27944,27945,27946,
8678527947,27948,27949,27950,27951,27952,27953,27954,27955,27956,27957,27958,
8678627959,27960,27961,27962,27963,27964,27965,27966,27967,27968,27969,27970,
8678727971,27972,27973,27974,27975,27976,27977,27978,27979,27980,27981,27982,
8678827983,27984,27985,27986,27987,27988,27989,27990,27991,27992,27993,27994,
8678927995,27996,27997,27998,27999,28000,28001,28002,28003,28004,28005,28006,
8679028007,28008,28009,28010,28011,28012,28013,28014,28015,28016,28017,28018,
8679128019,28020,28021,28022,28023,28024,28025,28026,28027,28028,28029,28030,
8679228031,28032,28033,28034,28035,28036,28037,28038,28039,28040,28041,28042,
8679328043,28044,28045,28046,28047,28048,28049,28050,28051,28052,28053,28054,
8679428055,28056,28057,28058,28059,28060,28061,28062,28063,28064,28065,28066,
8679528067,28068,28069,28070,28071,28072,28073,28074,28075,28076,28077,28078,
8679628079,28080,28081,28082,28083,28084,28085,28086,28087,28088,28089,28090,
8679728091,28092,28093,28094,28095,28096,28097,28098,28099,28100,28101,28102,
8679828103,28104,28105,28106,28107,28108,28109,28110,28111,28112,28113,28114,
8679928115,28116,28117,28118,28119,28120,28121,28122,28123,28124,28125,28126,
8680028127,28128,28129,28130,28131,28132,28133,28134,28135,28136,28137,28138,
8680128139,28140,28141,28142,28143,28144,28145,28146,28147,28148,28149,28150,
8680228151,28152,28153,28154,28155,28156,28157,28158,28159,28160,28161,28162,
8680328163,28164,28165,28166,28167,28168,28169,28170,28171,28172,28173,28174,
8680428175,28176,28177,28178,28179,28180,28181,28182,28183,28184,28185,28186,
8680528187,28188,28189,28190,28191,28192,28193,28194,28195,28196,28197,28198,
8680628199,28200,28201,28202,28203,28204,28205,28206,28207,28208,28209,28210,
8680728211,28212,28213,28214,28215,28216,28217,28218,28219,28220,28221,28222,
8680828223,28224,28225,28226,28227,28228,28229,28230,28231,28232,28233,28234,
8680928235,28236,28237,28238,28239,28240,28241,28242,28243,28244,28245,28246,
8681028247,28248,28249,28250,28251,28252,28253,28254,28255,28256,28257,28258,
8681128259,28260,28261,28262,28263,28264,28265,28266,28267,28268,28269,28270,
8681228271,28272,28273,28274,28275,28276,28277,28278,28279,28280,28281,28282,
8681328283,28284,28285,28286,28287,28288,28289,28290,28291,28292,28293,28294,
8681428295,28296,28297,28298,28299,28300,28301,28302,28303,28304,28305,28306,
8681528307,28308,28309,28310,28311,28312,28313,28314,28315,28316,28317,28318,
8681628319,28320,28321,28322,28323,28324,28325,28326,28327,28328,28329,28330,
8681728331,28332,28333,28334,28335,28336,28337,28338,28339,28340,28341,28342,
8681828343,28344,28345,28346,28347,28348,28349,28350,28351,28352,28353,28354,
8681928355,28356,28357,28358,28359,28360,28361,28362,28363,28364,28365,28366,
8682028367,28368,28369,28370,28371,28372,28373,28374,28375,28376,28377,28378,
8682128379,28380,28381,28382,28383,28384,28385,28386,28387,28388,28389,28390,
8682228391,28392,28393,28394,28395,28396,28397,28398,28399,28400,28401,28402,
8682328403,28404,28405,28406,28407,28408,28409,28410,28411,28412,28413,28414,
8682428415,28416,28417,28418,28419,28420,28421,28422,28423,28424,28425,28426,
8682528427,28428,28429,28430,28431,28432,28433,28434,28435,28436,28437,28438,
8682628439,28440,28441,28442,28443,28444,28445,28446,28447,28448,28449,28450,
8682728451,28452,28453,28454,28455,28456,28457,28458,28459,28460,28461,28462,
8682828463,28464,28465,28466,28467,28468,28469,28470,28471,28472,28473,28474,
8682928475,28476,28477,28478,28479,28480,28481,28482,28483,28484,28485,28486,
8683028487,28488,28489,28490,28491,28492,28493,28494,28495,28496,28497,28498,
8683128499,28500,28501,28502,28503,28504,28505,28506,28507,28508,28509,28510,
8683228511,28512,28513,28514,28515,28516,28517,28518,28519,28520,28521,28522,
8683328523,28524,28525,28526,28527,28528,28529,28530,28531,28532,28533,28534,
8683428535,28536,28537,28538,28539,28540,28541,28542,28543,28544,28545,28546,
8683528547,28548,28549,28550,28551,28552,28553,28554,28555,28556,28557,28558,
8683628559,28560,28561,28562,28563,28564,28565,28566,28567,28568,28569,28570,
8683728571,28572,28573,28574,28575,28576,28577,28578,28579,28580,28581,28582,
8683828583,28584,28585,28586,28587,28588,28589,28590,28591,28592,28593,28594,
8683928595,28596,28597,28598,28599,28600,28601,28602,28603,28604,28605,28606,
8684028607,28608,28609,28610,28611,28612,28613,28614,28615,28616,28617,28618,
8684128619,28620,28621,28622,28623,28624,28625,28626,28627,28628,28629,28630,
8684228631,28632,28633,28634,28635,28636,28637,28638,28639,28640,28641,28642,
8684328643,28644,28645,28646,28647,28648,28649,28650,28651,28652,28653,28654,
8684428655,28656,28657,28658,28659,28660,28661,28662,28663,28664,28665,28666,
8684528667,28668,28669,28670,28671,28672,28673,28674,28675,28676,28677,28678,
8684628679,28680,28681,28682,28683,28684,28685,28686,28687,28688,28689,28690,
8684728691,28692,28693,28694,28695,28696,28697,28698,28699,28700,28701,28702,
8684828703,28704,28705,28706,28707,28708,28709,28710,28711,28712,28713,28714,
8684928715,28716,28717,28718,28719,28720,28721,28722,28723,28724,28725,28726,
8685028727,28728,28729,28730,28731,28732,28733,28734,28735,28736,28737,28738,
8685128739,28740,28741,28742,28743,28744,28745,28746,28747,28748,28749,28750,
8685228751,28752,28753,28754,28755,28756,28757,28758,28759,28760,28761,28762,
8685328763,28764,28765,28766,28767,28768,28769,28770,28771,28772,28773,28774,
8685428775,28776,28777,28778,28779,28780,28781,28782,28783,28784,28785,28786,
8685528787,28788,28789,28790,28791,28792,28793,28794,28795,28796,28797,28798,
8685628799,28800,28801,28802,28803,28804,28805,28806,28807,28808,28809,28810,
8685728811,28812,28813,28814,28815,28816,28817,28818,28819,28820,28821,28822,
8685828823,28824,28825,28826,28827,28828,28829,28830,28831,28832,28833,28834,
8685928835,28836,28837,28838,28839,28840,28841,28842,28843,28844,28845,28846,
8686028847,28848,28849,28850,28851,28852,28853,28854,28855,28856,28857,28858,
8686128859,28860,28861,28862,28863,28864,28865,28866,28867,28868,28869,28870,
8686228871,28872,28873,28874,28875,28876,28877,28878,28879,28880,28881,28882,
8686328883,28884,28885,28886,28887,28888,28889,28890,28891,28892,28893,28894,
8686428895,28896,28897,28898,28899,28900,28901,28902,28903,28904,28905,28906,
8686528907,28908,28909,28910,28911,28912,28913,28914,28915,28916,28917,28918,
8686628919,28920,28921,28922,28923,28924,28925,28926,28927,28928,28929,28930,
8686728931,28932,28933,28934,28935,28936,28937,28938,28939,28940,28941,28942,
8686828943,28944,28945,28946,28947,28948,28949,28950,28951,28952,28953,28954,
8686928955,28956,28957,28958,28959,28960,28961,28962,28963,28964,28965,28966,
8687028967,28968,28969,28970,28971,28972,28973,28974,28975,28976,28977,28978,
8687128979,28980,28981,28982,28983,28984,28985,28986,28987,28988,28989,28990,
8687228991,28992,28993,28994,28995,28996,28997,28998,28999,29000,29001,29002,
8687329003,29004,29005,29006,29007,29008,29009,29010,29011,29012,29013,29014,
8687429015,29016,29017,29018,29019,29020,29021,29022,29023,29024,29025,29026,
8687529027,29028,29029,29030,29031,29032,29033,29034,29035,29036,29037,29038,
8687629039,29040,29041,29042,29043,29044,29045,29046,29047,29048,29049,29050,
8687729051,29052,29053,29054,29055,29056,29057,29058,29059,29060,29061,29062,
8687829063,29064,29065,29066,29067,29068,29069,29070,29071,29072,29073,29074,
8687929075,29076,29077,29078,29079,29080,29081,29082,29083,29084,29085,29086,
8688029087,29088,29089,29090,29091,29092,29093,29094,29095,29096,29097,29098,
8688129099,29100,29101,29102,29103,29104,29105,29106,29107,29108,29109,29110,
8688229111,29112,29113,29114,29115,29116,29117,29118,29119,29120,29121,29122,
8688329123,29124,29125,29126,29127,29128,29129,29130,29131,29132,29133,29134,
8688429135,29136,29137,29138,29139,29140,29141,29142,29143,29144,29145,29146,
8688529147,29148,29149,29150,29151,29152,29153,29154,29155,29156,29157,29158,
8688629159,29160,29161,29162,29163,29164,29165,29166,29167,29168,29169,29170,
8688729171,29172,29173,29174,29175,29176,29177,29178,29179,29180,29181,29182,
8688829183,29184,29185,29186,29187,29188,29189,29190,29191,29192,29193,29194,
8688929195,29196,29197,29198,29199,29200,29201,29202,29203,29204,29205,29206,
8689029207,29208,29209,29210,29211,29212,29213,29214,29215,29216,29217,29218,
8689129219,29220,29221,29222,29223,29224,29225,29226,29227,29228,29229,29230,
8689229231,29232,29233,29234,29235,29236,29237,29238,29239,29240,29241,29242,
8689329243,29244,29245,29246,29247,29248,29249,29250,29251,29252,29253,29254,
8689429255,29256,29257,29258,29259,29260,29261,29262,29263,29264,29265,29266,
8689529267,29268,29269,29270,29271,29272,29273,29274,29275,29276,29277,29278,
8689629279,29280,29281,29282,29283,29284,29285,29286,29287,29288,29289,29290,
8689729291,29292,29293,29294,29295,29296,29297,29298,29299,29300,29301,29302,
8689829303,29304,29305,29306,29307,29308,29309,29310,29311,29312,29313,29314,
8689929315,29316,29317,29318,29319,29320,29321,29322,29323,29324,29325,29326,
8690029327,29328,29329,29330,29331,29332,29333,29334,29335,29336,29337,29338,
8690129339,29340,29341,29342,29343,29344,29345,29346,29347,29348,29349,29350,
8690229351,29352,29353,29354,29355,29356,29357,29358,29359,29360,29361,29362,
8690329363,29364,29365,29366,29367,29368,29369,29370,29371,29372,29373,29374,
8690429375,29376,29377,29378,29379,29380,29381,29382,29383,29384,29385,29386,
8690529387,29388,29389,29390,29391,29392,29393,29394,29395,29396,29397,29398,
8690629399,29400,29401,29402,29403,29404,29405,29406,29407,29408,29409,29410,
8690729411,29412,29413,29414,29415,29416,29417,29418,29419,29420,29421,29422,
8690829423,29424,29425,29426,29427,29428,29429,29430,29431,29432,29433,29434,
8690929435,29436,29437,29438,29439,29440,29441,29442,29443,29444,29445,29446,
8691029447,29448,29449,29450,29451,29452,29453,29454,29455,29456,29457,29458,
8691129459,29460,29461,29462,29463,29464,29465,29466,29467,29468,29469,29470,
8691229471,29472,29473,29474,29475,29476,29477,29478,29479,29480,29481,29482,
8691329483,29484,29485,29486,29487,29488,29489,29490,29491,29492,29493,29494,
8691429495,29496,29497,29498,29499,29500,29501,29502,29503,29504,29505,29506,
8691529507,29508,29509,29510,29511,29512,29513,29514,29515,29516,29517,29518,
8691629519,29520,29521,29522,29523,29524,29525,29526,29527,29528,29529,29530,
8691729531,29532,29533,29534,29535,29536,29537,29538,29539,29540,29541,29542,
8691829543,29544,29545,29546,29547,29548,29549,29550,29551,29552,29553,29554,
8691929555,29556,29557,29558,29559,29560,29561,29562,29563,29564,29565,29566,
8692029567,29568,29569,29570,29571,29572,29573,29574,29575,29576,29577,29578,
8692129579,29580,29581,29582,29583,29584,29585,29586,29587,29588,29589,29590,
8692229591,29592,29593,29594,29595,29596,29597,29598,29599,29600,29601,29602,
8692329603,29604,29605,29606,29607,29608,29609,29610,29611,29612,29613,29614,
8692429615,29616,29617,29618,29619,29620,29621,29622,29623,29624,29625,29626,
8692529627,29628,29629,29630,29631,29632,29633,29634,29635,29636,29637,29638,
8692629639,29640,29641,29642,29643,29644,29645,29646,29647,29648,29649,29650,
8692729651,29652,29653,29654,29655,29656,29657,29658,29659,29660,29661,29662,
8692829663,29664,29665,29666,29667,29668,29669,29670,29671,29672,29673,29674,
8692929675,29676,29677,29678,29679,29680,29681,29682,29683,29684,29685,29686,
8693029687,29688,29689,29690,29691,29692,29693,29694,29695,29696,29697,29698,
8693129699,29700,29701,29702,29703,29704,29705,29706,29707,29708,29709,29710,
8693229711,29712,29713,29714,29715,29716,29717,29718,29719,29720,29721,29722,
8693329723,29724,29725,29726,29727,29728,29729,29730,29731,29732,29733,29734,
8693429735,29736,29737,29738,29739,29740,29741,29742,29743,29744,29745,29746,
8693529747,29748,29749,29750,29751,29752,29753,29754,29755,29756,29757,29758,
8693629759,29760,29761,29762,29763,29764,29765,29766,29767,29768,29769,29770,
8693729771,29772,29773,29774,29775,29776,29777,29778,29779,29780,29781,29782,
8693829783,29784,29785,29786,29787,29788,29789,29790,29791,29792,29793,29794,
8693929795,29796,29797,29798,29799,29800,29801,29802,29803,29804,29805,29806,
8694029807,29808,29809,29810,29811,29812,29813,29814,29815,29816,29817,29818,
8694129819,29820,29821,29822,29823,29824,29825,29826,29827,29828,29829,29830,
8694229831,29832,29833,29834,29835,29836,29837,29838,29839,29840,29841,29842,
8694329843,29844,29845,29846,29847,29848,29849,29850,29851,29852,29853,29854,
8694429855,29856,29857,29858,29859,29860,29861,29862,29863,29864,29865,29866,
8694529867,29868,29869,29870,29871,29872,29873,29874,29875,29876,29877,29878,
8694629879,29880,29881,29882,29883,29884,29885,29886,29887,29888,29889,29890,
8694729891,29892,29893,29894,29895,29896,29897,29898,29899,29900,29901,29902,
8694829903,29904,29905,29906,29907,29908,29909,29910,29911,29912,29913,29914,
8694929915,29916,29917,29918,29919,29920,29921,29922,29923,29924,29925,29926,
8695029927,29928,29929,29930,29931,29932,29933,29934,29935,29936,29937,29938,
8695129939,29940,29941,29942,29943,29944,29945,29946,29947,29948,29949,29950,
8695229951,29952,29953,29954,29955,29956,29957,29958,29959,29960,29961,29962,
8695329963,29964,29965,29966,29967,29968,29969,29970,29971,29972,29973,29974,
8695429975,29976,29977,29978,29979,29980,29981,29982,29983,29984,29985,29986,
8695529987,29988,29989,29990,29991,29992,29993,29994,29995,29996,29997,29998,
8695629999,30000,30001,30002,30003,30004,30005,30006,30007,30008,30009,30010,
8695730011,30012,30013,30014,30015,30016,30017,30018,30019,30020,30021,30022,
8695830023,30024,30025,30026,30027,30028,30029,30030,30031,30032,30033,30034,
8695930035,30036,30037,30038,30039,30040,30041,30042,30043,30044,30045,30046,
8696030047,30048,30049,30050,30051,30052,30053,30054,30055,30056,30057,30058,
8696130059,30060,30061,30062,30063,30064,30065,30066,30067,30068,30069,30070,
8696230071,30072,30073,30074,30075,30076,30077,30078,30079,30080,30081,30082,
8696330083,30084,30085,30086,30087,30088,30089,30090,30091,30092,30093,30094,
8696430095,30096,30097,30098,30099,30100,30101,30102,30103,30104,30105,30106,
8696530107,30108,30109,30110,30111,30112,30113,30114,30115,30116,30117,30118,
8696630119,30120,30121,30122,30123,30124,30125,30126,30127,30128,30129,30130,
8696730131,30132,30133,30134,30135,30136,30137,30138,30139,30140,30141,30142,
8696830143,30144,30145,30146,30147,30148,30149,30150,30151,30152,30153,30154,
8696930155,30156,30157,30158,30159,30160,30161,30162,30163,30164,30165,30166,
8697030167,30168,30169,30170,30171,30172,30173,30174,30175,30176,30177,30178,
8697130179,30180,30181,30182,30183,30184,30185,30186,30187,30188,30189,30190,
8697230191,30192,30193,30194,30195,30196,30197,30198,30199,30200,30201,30202,
8697330203,30204,30205,30206,30207,30208,30209,30210,30211,30212,30213,30214,
8697430215,30216,30217,30218,30219,30220,30221,30222,30223,30224,30225,30226,
8697530227,30228,30229,30230,30231,30232,30233,30234,30235,30236,30237,30238,
8697630239,30240,30241,30242,30243,30244,30245,30246,30247,30248,30249,30250,
8697730251,30252,30253,30254,30255,30256,30257,30258,30259,30260,30261,30262,
8697830263,30264,30265,30266,30267,30268,30269,30270,30271,30272,30273,30274,
8697930275,30276,30277,30278,30279,30280,30281,30282,30283,30284,30285,30286,
8698030287,30288,30289,30290,30291,30292,30293,30294,30295,30296,30297,30298,
8698130299,30300,30301,30302,30303,30304,30305,30306,30307,30308,30309,30310,
8698230311,30312,30313,30314,30315,30316,30317,30318,30319,30320,30321,30322,
8698330323,30324,30325,30326,30327,30328,30329,30330,30331,30332,30333,30334,
8698430335,30336,30337,30338,30339,30340,30341,30342,30343,30344,30345,30346,
8698530347,30348,30349,30350,30351,30352,30353,30354,30355,30356,30357,30358,
8698630359,30360,30361,30362,30363,30364,30365,30366,30367,30368,30369,30370,
8698730371,30372,30373,30374,30375,30376,30377,30378,30379,30380,30381,30382,
8698830383,30384,30385,30386,30387,30388,30389,30390,30391,30392,30393,30394,
8698930395,30396,30397,30398,30399,30400,30401,30402,30403,30404,30405,30406,
8699030407,30408,30409,30410,30411,30412,30413,30414,30415,30416,30417,30418,
8699130419,30420,30421,30422,30423,30424,30425,30426,30427,30428,30429,30430,
8699230431,30432,30433,30434,30435,30436,30437,30438,30439,30440,30441,30442,
8699330443,30444,30445,30446,30447,30448,30449,30450,30451,30452,30453,30454,
8699430455,30456,30457,30458,30459,30460,30461,30462,30463,30464,30465,30466,
8699530467,30468,30469,30470,30471,30472,30473,30474,30475,30476,30477,30478,
8699630479,30480,30481,30482,30483,30484,30485,30486,30487,30488,30489,30490,
8699730491,30492,30493,30494,30495,30496,30497,30498,30499,30500,30501,30502,
8699830503,30504,30505,30506,30507,30508,30509,30510,30511,30512,30513,30514,
8699930515,30516,30517,30518,30519,30520,30521,30522,30523,30524,30525,30526,
8700030527,30528,30529,30530,30531,30532,30533,30534,30535,30536,30537,30538,
8700130539,30540,30541,30542,30543,30544,30545,30546,30547,30548,30549,30550,
8700230551,30552,30553,30554,30555,30556,30557,30558,30559,30560,30561,30562,
8700330563,30564,30565,30566,30567,30568,30569,30570,30571,30572,30573,30574,
8700430575,30576,30577,30578,30579,30580,30581,30582,30583,30584,30585,30586,
8700530587,30588,30589,30590,30591,30592,30593,30594,30595,30596,30597,30598,
8700630599,30600,30601,30602,30603,30604,30605,30606,30607,30608,30609,30610,
8700730611,30612,30613,30614,30615,30616,30617,30618,30619,30620,30621,30622,
8700830623,30624,30625,30626,30627,30628,30629,30630,30631,30632,30633,30634,
8700930635,30636,30637,30638,30639,30640,30641,30642,30643,30644,30645,30646,
8701030647,30648,30649,30650,30651,30652,30653,30654,30655,30656,30657,30658,
8701130659,30660,30661,30662,30663,30664,30665,30666,30667,30668,30669,30670,
8701230671,30672,30673,30674,30675,30676,30677,30678,30679,30680,30681,30682,
8701330683,30684,30685,30686,30687,30688,30689,30690,30691,30692,30693,30694,
8701430695,30696,30697,30698,30699,30700,30701,30702,30703,30704,30705,30706,
8701530707,30708,30709,30710,30711,30712,30713,30714,30715,30716,30717,30718,
8701630719,30720,30721,30722,30723,30724,30725,30726,30727,30728,30729,30730,
8701730731,30732,30733,30734,30735,30736,30737,30738,30739,30740,30741,30742,
8701830743,30744,30745,30746,30747,30748,30749,30750,30751,30752,30753,30754,
8701930755,30756,30757,30758,30759,30760,30761,30762,30763,30764,30765,30766,
8702030767,30768,30769,30770,30771,30772,30773,30774,30775,30776,30777,30778,
8702130779,30780,30781,30782,30783,30784,30785,30786,30787,30788,30789,30790,
8702230791,30792,30793,30794,30795,30796,30797,30798,30799,30800,30801,30802,
8702330803,30804,30805,30806,30807,30808,30809,30810,30811,30812,30813,30814,
8702430815,30816,30817,30818,30819,30820,30821,30822,30823,30824,30825,30826,
8702530827,30828,30829,30830,30831,30832,30833,30834,30835,30836,30837,30838,
8702630839,30840,30841,30842,30843,30844,30845,30846,30847,30848,30849,30850,
8702730851,30852,30853,30854,30855,30856,30857,30858,30859,30860,30861,30862,
8702830863,30864,30865,30866,30867,30868,30869,30870,30871,30872,30873,30874,
8702930875,30876,30877,30878,30879,30880,30881,30882,30883,30884,30885,30886,
8703030887,30888,30889,30890,30891,30892,30893,30894,30895,30896,30897,30898,
8703130899,30900,30901,30902,30903,30904,30905,30906,30907,30908,30909,30910,
8703230911,30912,30913,30914,30915,30916,30917,30918,30919,30920,30921,30922,
8703330923,30924,30925,30926,30927,30928,30929,30930,30931,30932,30933,30934,
8703430935,30936,30937,30938,30939,30940,30941,30942,30943,30944,30945,30946,
8703530947,30948,30949,30950,30951,30952,30953,30954,30955,30956,30957,30958,
8703630959,30960,30961,30962,30963,30964,30965,30966,30967,30968,30969,30970,
8703730971,30972,30973,30974,30975,30976,30977,30978,30979,30980,30981,30982,
8703830983,30984,30985,30986,30987,30988,30989,30990,30991,30992,30993,30994,
8703930995,30996,30997,30998,30999,31000,31001,31002,31003,31004,31005,31006,
8704031007,31008,31009,31010,31011,31012,31013,31014,31015,31016,31017,31018,
8704131019,31020,31021,31022,31023,31024,31025,31026,31027,31028,31029,31030,
8704231031,31032,31033,31034,31035,31036,31037,31038,31039,31040,31041,31042,
8704331043,31044,31045,31046,31047,31048,31049,31050,31051,31052,31053,31054,
8704431055,31056,31057,31058,31059,31060,31061,31062,31063,31064,31065,31066,
8704531067,31068,31069,31070,31071,31072,31073,31074,31075,31076,31077,31078,
8704631079,31080,31081,31082,31083,31084,31085,31086,31087,31088,31089,31090,
8704731091,31092,31093,31094,31095,31096,31097,31098,31099,31100,31101,31102,
8704831103,31104,31105,31106,31107,31108,31109,31110,31111,31112,31113,31114,
8704931115,31116,31117,31118,31119,31120,31121,31122,31123,31124,31125,31126,
8705031127,31128,31129,31130,31131,31132,31133,31134,31135,31136,31137,31138,
8705131139,31140,31141,31142,31143,31144,31145,31146,31147,31148,31149,31150,
8705231151,31152,31153,31154,31155,31156,31157,31158,31159,31160,31161,31162,
8705331163,31164,31165,31166,31167,31168,31169,31170,31171,31172,31173,31174,
8705431175,31176,31177,31178,31179,31180,31181,31182,31183,31184,31185,31186,
8705531187,31188,31189,31190,31191,31192,31193,31194,31195,31196,31197,31198,
8705631199,31200,31201,31202,31203,31204,31205,31206,31207,31208,31209,31210,
8705731211,31212,31213,31214,31215,31216,31217,31218,31219,31220,31221,31222,
8705831223,31224,31225,31226,31227,31228,31229,31230,31231,31232,31233,31234,
8705931235,31236,31237,31238,31239,31240,31241,31242,31243,31244,31245,31246,
8706031247,31248,31249,31250,31251,31252,31253,31254,31255,31256,31257,31258,
8706131259,31260,31261,31262,31263,31264,31265,31266,31267,31268,31269,31270,
8706231271,31272,31273,31274,31275,31276,31277,31278,31279,31280,31281,31282,
8706331283,31284,31285,31286,31287,31288,31289,31290,31291,31292,31293,31294,
8706431295,31296,31297,31298,31299,31300,31301,31302,31303,31304,31305,31306,
8706531307,31308,31309,31310,31311,31312,31313,31314,31315,31316,31317,31318,
8706631319,31320,31321,31322,31323,31324,31325,31326,31327,31328,31329,31330,
8706731331,31332,31333,31334,31335,31336,31337,31338,31339,31340,31341,31342,
8706831343,31344,31345,31346,31347,31348,31349,31350,31351,31352,31353,31354,
8706931355,31356,31357,31358,31359,31360,31361,31362,31363,31364,31365,31366,
8707031367,31368,31369,31370,31371,31372,31373,31374,31375,31376,31377,31378,
8707131379,31380,31381,31382,31383,31384,31385,31386,31387,31388,31389,31390,
8707231391,31392,31393,31394,31395,31396,31397,31398,31399,31400,31401,31402,
8707331403,31404,31405,31406,31407,31408,31409,31410,31411,31412,31413,31414,
8707431415,31416,31417,31418,31419,31420,31421,31422,31423,31424,31425,31426,
8707531427,31428,31429,31430,31431,31432,31433,31434,31435,31436,31437,31438,
8707631439,31440,31441,31442,31443,31444,31445,31446,31447,31448,31449,31450,
8707731451,31452,31453,31454,31455,31456,31457,31458,31459,31460,31461,31462,
8707831463,31464,31465,31466,31467,31468,31469,31470,31471,31472,31473,31474,
8707931475,31476,31477,31478,31479,31480,31481,31482,31483,31484,31485,31486,
8708031487,31488,31489,31490,31491,31492,31493,31494,31495,31496,31497,31498,
8708131499,31500,31501,31502,31503,31504,31505,31506,31507,31508,31509,31510,
8708231511,31512,31513,31514,31515,31516,31517,31518,31519,31520,31521,31522,
8708331523,31524,31525,31526,31527,31528,31529,31530,31531,31532,31533,31534,
8708431535,31536,31537,31538,31539,31540,31541,31542,31543,31544,31545,31546,
8708531547,31548,31549,31550,31551,31552,31553,31554,31555,31556,31557,31558,
8708631559,31560,31561,31562,31563,31564,31565,31566,31567,31568,31569,31570,
8708731571,31572,31573,31574,31575,31576,31577,31578,31579,31580,31581,31582,
8708831583,31584,31585,31586,31587,31588,31589,31590,31591,31592,31593,31594,
8708931595,31596,31597,31598,31599,31600,31601,31602,31603,31604,31605,31606,
8709031607,31608,31609,31610,31611,31612,31613,31614,31615,31616,31617,31618,
8709131619,31620,31621,31622,31623,31624,31625,31626,31627,31628,31629,31630,
8709231631,31632,31633,31634,31635,31636,31637,31638,31639,31640,31641,31642,
8709331643,31644,31645,31646,31647,31648,31649,31650,31651,31652,31653,31654,
8709431655,31656,31657,31658,31659,31660,31661,31662,31663,31664,31665,31666,
8709531667,31668,31669,31670,31671,31672,31673,31674,31675,31676,31677,31678,
8709631679,31680,31681,31682,31683,31684,31685,31686,31687,31688,31689,31690,
8709731691,31692,31693,31694,31695,31696,31697,31698,31699,31700,31701,31702,
8709831703,31704,31705,31706,31707,31708,31709,31710,31711,31712,31713,31714,
8709931715,31716,31717,31718,31719,31720,31721,31722,31723,31724,31725,31726,
8710031727,31728,31729,31730,31731,31732,31733,31734,31735,31736,31737,31738,
8710131739,31740,31741,31742,31743,31744,31745,31746,31747,31748,31749,31750,
8710231751,31752,31753,31754,31755,31756,31757,31758,31759,31760,31761,31762,
8710331763,31764,31765,31766,31767,31768,31769,31770,31771,31772,31773,31774,
8710431775,31776,31777,31778,31779,31780,31781,31782,31783,31784,31785,31786,
8710531787,31788,31789,31790,31791,31792,31793,31794,31795,31796,31797,31798,
8710631799,31800,31801,31802,31803,31804,31805,31806,31807,31808,31809,31810,
8710731811,31812,31813,31814,31815,31816,31817,31818,31819,31820,31821,31822,
8710831823,31824,31825,31826,31827,31828,31829,31830,31831,31832,31833,31834,
8710931835,31836,31837,31838,31839,31840,31841,31842,31843,31844,31845,31846,
8711031847,31848,31849,31850,31851,31852,31853,31854,31855,31856,31857,31858,
8711131859,31860,31861,31862,31863,31864,31865,31866,31867,31868,31869,31870,
8711231871,31872,31873,31874,31875,31876,31877,31878,31879,31880,31881,31882,
8711331883,31884,31885,31886,31887,31888,31889,31890,31891,31892,31893,31894,
8711431895,31896,31897,31898,31899,31900,31901,31902,31903,31904,31905,31906,
8711531907,31908,31909,31910,31911,31912,31913,31914,31915,31916,31917,31918,
8711631919,31920,31921,31922,31923,31924,31925,31926,31927,31928,31929,31930,
8711731931,31932,31933,31934,31935,31936,31937,31938,31939,31940,31941,31942,
8711831943,31944,31945,31946,31947,31948,31949,31950,31951,31952,31953,31954,
8711931955,31956,31957,31958,31959,31960,31961,31962,31963,31964,31965,31966,
8712031967,31968,31969,31970,31971,31972,31973,31974,31975,31976,31977,31978,
8712131979,31980,31981,31982,31983,31984,31985,31986,31987,31988,31989,31990,
8712231991,31992,31993,31994,31995,31996,31997,31998,31999,32000,32001,32002,
8712332003,32004,32005,32006,32007,32008,32009,32010,32011,32012,32013,32014,
8712432015,32016,32017,32018,32019,32020,32021,32022,32023,32024,32025,32026,
8712532027,32028,32029,32030,32031,32032,32033,32034,32035,32036,32037,32038,
8712632039,32040,32041,32042,32043,32044,32045,32046,32047,32048,32049,32050,
8712732051,32052,32053,32054,32055,32056,32057,32058,32059,32060,32061,32062,
8712832063,32064,32065,32066,32067,32068,32069,32070,32071,32072,32073,32074,
8712932075,32076,32077,32078,32079,32080,32081,32082,32083,32084,32085,32086,
8713032087,32088,32089,32090,32091,32092,32093,32094,32095,32096,32097,32098,
8713132099,32100,32101,32102,32103,32104,32105,32106,32107,32108,32109,32110,
8713232111,32112,32113,32114,32115,32116,32117,32118,32119,32120,32121,32122,
8713332123,32124,32125,32126,32127,32128,32129,32130,32131,32132,32133,32134,
8713432135,32136,32137,32138,32139,32140,32141,32142,32143,32144,32145,32146,
8713532147,32148,32149,32150,32151,32152,32153,32154,32155,32156,32157,32158,
8713632159,32160,32161,32162,32163,32164,32165,32166,32167,32168,32169,32170,
8713732171,32172,32173,32174,32175,32176,32177,32178,32179,32180,32181,32182,
8713832183,32184,32185,32186,32187,32188,32189,32190,32191,32192,32193,32194,
8713932195,32196,32197,32198,32199,32200,32201,32202,32203,32204,32205,32206,
8714032207,32208,32209,32210,32211,32212,32213,32214,32215,32216,32217,32218,
8714132219,32220,32221,32222,32223,32224,32225,32226,32227,32228,32229,32230,
8714232231,32232,32233,32234,32235,32236,32237,32238,32239,32240,32241,32242,
8714332243,32244,32245,32246,32247,32248,32249,32250,32251,32252,32253,32254,
8714432255,32256,32257,32258,32259,32260,32261,32262,32263,32264,32265,32266,
8714532267,32268,32269,32270,32271,32272,32273,32274,32275,32276,32277,32278,
8714632279,32280,32281,32282,32283,32284,32285,32286,32287,32288,32289,32290,
8714732291,32292,32293,32294,32295,32296,32297,32298,32299,32300,32301,32302,
8714832303,32304,32305,32306,32307,32308,32309,32310,32311,32312,32313,32314,
8714932315,32316,32317,32318,32319,32320,32321,32322,32323,32324,32325,32326,
8715032327,32328,32329,32330,32331,32332,32333,32334,32335,32336,32337,32338,
8715132339,32340,32341,32342,32343,32344,32345,32346,32347,32348,32349,32350,
8715232351,32352,32353,32354,32355,32356,32357,32358,32359,32360,32361,32362,
8715332363,32364,32365,32366,32367,32368,32369,32370,32371,32372,32373,32374,
8715432375,32376,32377,32378,32379,32380,32381,32382,32383,32384,32385,32386,
8715532387,32388,32389,32390,32391,32392,32393,32394,32395,32396,32397,32398,
8715632399,32400,32401,32402,32403,32404,32405,32406,32407,32408,32409,32410,
8715732411,32412,32413,32414,32415,32416,32417,32418,32419,32420,32421,32422,
8715832423,32424,32425,32426,32427,32428,32429,32430,32431,32432,32433,32434,
8715932435,32436,32437,32438,32439,32440,32441,32442,32443,32444,32445,32446,
8716032447,32448,32449,32450,32451,32452,32453,32454,32455,32456,32457,32458,
8716132459,32460,32461,32462,32463,32464,32465,32466,32467,32468,32469,32470,
8716232471,32472,32473,32474,32475,32476,32477,32478,32479,32480,32481,32482,
8716332483,32484,32485,32486,32487,32488,32489,32490,32491,32492,32493,32494,
8716432495,32496,32497,32498,32499,32500,32501,32502,32503,32504,32505,32506,
8716532507,32508,32509,32510,32511,32512,32513,32514,32515,32516,32517,32518,
8716632519,32520,32521,32522,32523,32524,32525,32526,32527,32528,32529,32530,
8716732531,32532,32533,32534,32535,32536,32537,32538,32539,32540,32541,32542,
8716832543,32544,32545,32546,32547,32548,32549,32550,32551,32552,32553,32554,
8716932555,32556,32557,32558,32559,32560,32561,32562,32563,32564,32565,32566,
8717032567,32568,32569,32570,32571,32572,32573,32574,32575,32576,32577,32578,
8717132579,32580,32581,32582,32583,32584,32585,32586,32587,32588,32589,32590,
8717232591,32592,32593,32594,32595,32596,32597,32598,32599,32600,32601,32602,
8717332603,32604,32605,32606,32607,32608,32609,32610,32611,32612,32613,32614,
8717432615,32616,32617,32618,32619,32620,32621,32622,32623,32624,32625,32626,
8717532627,32628,32629,32630,32631,32632,32633,32634,32635,32636,32637,32638,
8717632639,32640,32641,32642,32643,32644,32645,32646,32647,32648,32649,32650,
8717732651,32652,32653,32654,32655,32656,32657,32658,32659,32660,32661,32662,
8717832663,32664,32665,32666,32667,32668,32669,32670,32671,32672,32673,32674,
8717932675,32676,32677,32678,32679,32680,32681,32682,32683,32684,32685,32686,
8718032687,32688,32689,32690,32691,32692,32693,32694,32695,32696,32697,32698,
8718132699,32700,32701,32702,32703,32704,32705,32706,32707,32708,32709,32710,
8718232711,32712,32713,32714,32715,32716,32717,32718,32719,32720,32721,32722,
8718332723,32724,32725,32726,32727,32728,32729,32730,32731,32732,32733,32734,
8718432735,32736,32737,32738,32739,32740,32741,32742,32743,32744,32745,32746,
8718532747,32748,32749,32750,32751,32752,32753,32754,32755,32756,32757,32758,
8718632759,32760,32761,32762,32763,32764,32765,32766,32767,32768L,32769L,32770L,
8718732771L,32772L,32773L,32774L,32775L,32776L,32777L,32778L,32779L,32780L,
8718832781L,32782L,32783L,32784L,32785L,32786L,32787L,32788L,32789L,32790L,
8718932791L,32792L,32793L,32794L,32795L,32796L,32797L,32798L,32799L,32800L,
8719032801L,32802L,32803L,32804L,32805L,32806L,32807L,32808L,32809L,32810L,
8719132811L,32812L,32813L,32814L,32815L,32816L,32817L,32818L,32819L,32820L,
8719232821L,32822L,32823L,32824L,32825L,32826L,32827L,32828L,32829L,32830L,
8719332831L,32832L,32833L,32834L,32835L,32836L,32837L,32838L,32839L,32840L,
8719432841L,32842L,32843L,32844L,32845L,32846L,32847L,32848L,32849L,32850L,
8719532851L,32852L,32853L,32854L,32855L,32856L,32857L,32858L,32859L,32860L,
8719632861L,32862L,32863L,32864L,32865L,32866L,32867L,32868L,32869L,32870L,
8719732871L,32872L,32873L,32874L,32875L,32876L,32877L,32878L,32879L,32880L,
8719832881L,32882L,32883L,32884L,32885L,32886L,32887L,32888L,32889L,32890L,
8719932891L,32892L,32893L,32894L,32895L,32896L,32897L,32898L,32899L,32900L,
8720032901L,32902L,32903L,32904L,32905L,32906L,32907L,32908L,32909L,32910L,
8720132911L,32912L,32913L,32914L,32915L,32916L,32917L,32918L,32919L,32920L,
8720232921L,32922L,32923L,32924L,32925L,32926L,32927L,32928L,32929L,32930L,
8720332931L,32932L,32933L,32934L,32935L,32936L,32937L,32938L,32939L,32940L,
8720432941L,32942L,32943L,32944L,32945L,32946L,32947L,32948L,32949L,32950L,
8720532951L,32952L,32953L,32954L,32955L,32956L,32957L,32958L,32959L,32960L,
8720632961L,32962L,32963L,32964L,32965L,32966L,32967L,32968L,32969L,32970L,
8720732971L,32972L,32973L,32974L,32975L,32976L,32977L,32978L,32979L,32980L,
8720832981L,32982L,32983L,32984L,32985L,32986L,32987L,32988L,32989L,32990L,
8720932991L,32992L,32993L,32994L,32995L,32996L,32997L,32998L,32999L,33000L,
8721033001L,33002L,33003L,33004L,33005L,33006L,33007L,33008L,33009L,33010L,
8721133011L,33012L,33013L,33014L,33015L,33016L,33017L,33018L,33019L,33020L,
8721233021L,33022L,33023L,33024L,33025L,33026L,33027L,33028L,33029L,33030L,
8721333031L,33032L,33033L,33034L,33035L,33036L,33037L,33038L,33039L,33040L,
8721433041L,33042L,33043L,33044L,33045L,33046L,33047L,33048L,33049L,33050L,
8721533051L,33052L,33053L,33054L,33055L,33056L,33057L,33058L,33059L,33060L,
8721633061L,33062L,33063L,33064L,33065L,33066L,33067L,33068L,33069L,33070L,
8721733071L,33072L,33073L,33074L,33075L,33076L,33077L,33078L,33079L,33080L,
8721833081L,33082L,33083L,33084L,33085L,33086L,33087L,33088L,33089L,33090L,
8721933091L,33092L,33093L,33094L,33095L,33096L,33097L,33098L,33099L,33100L,
8722033101L,33102L,33103L,33104L,33105L,33106L,33107L,33108L,33109L,33110L,
8722133111L,33112L,33113L,33114L,33115L,33116L,33117L,33118L,33119L,33120L,
8722233121L,33122L,33123L,33124L,33125L,33126L,33127L,33128L,33129L,33130L,
8722333131L,33132L,33133L,33134L,33135L,33136L,33137L,33138L,33139L,33140L,
8722433141L,33142L,33143L,33144L,33145L,33146L,33147L,33148L,33149L,33150L,
8722533151L,33152L,33153L,33154L,33155L,33156L,33157L,33158L,33159L,33160L,
8722633161L,33162L,33163L,33164L,33165L,33166L,33167L,33168L,33169L,33170L,
8722733171L,33172L,33173L,33174L,33175L,33176L,33177L,33178L,33179L,33180L,
8722833181L,33182L,33183L,33184L,33185L,33186L,33187L,33188L,33189L,33190L,
8722933191L,33192L,33193L,33194L,33195L,33196L,33197L,33198L,33199L,33200L,
8723033201L,33202L,33203L,33204L,33205L,33206L,33207L,33208L,33209L,33210L,
8723133211L,33212L,33213L,33214L,33215L,33216L,33217L,33218L,33219L,33220L,
8723233221L,33222L,33223L,33224L,33225L,33226L,33227L,33228L,33229L,33230L,
8723333231L,33232L,33233L,33234L,33235L,33236L,33237L,33238L,33239L,33240L,
8723433241L,33242L,33243L,33244L,33245L,33246L,33247L,33248L,33249L,33250L,
8723533251L,33252L,33253L,33254L,33255L,33256L,33257L,33258L,33259L,33260L,
8723633261L,33262L,33263L,33264L,33265L,33266L,33267L,33268L,33269L,33270L,
8723733271L,33272L,33273L,33274L,33275L,33276L,33277L,33278L,33279L,33280L,
8723833281L,33282L,33283L,33284L,33285L,33286L,33287L,33288L,33289L,33290L,
8723933291L,33292L,33293L,33294L,33295L,33296L,33297L,33298L,33299L,33300L,
8724033301L,33302L,33303L,33304L,33305L,33306L,33307L,33308L,33309L,33310L,
8724133311L,33312L,33313L,33314L,33315L,33316L,33317L,33318L,33319L,33320L,
8724233321L,33322L,33323L,33324L,33325L,33326L,33327L,33328L,33329L,33330L,
8724333331L,33332L,33333L,33334L,33335L,33336L,33337L,33338L,33339L,33340L,
8724433341L,33342L,33343L,33344L,33345L,33346L,33347L,33348L,33349L,33350L,
8724533351L,33352L,33353L,33354L,33355L,33356L,33357L,33358L,33359L,33360L,
8724633361L,33362L,33363L,33364L,33365L,33366L,33367L,33368L,33369L,33370L,
8724733371L,33372L,33373L,33374L,33375L,33376L,33377L,33378L,33379L,33380L,
8724833381L,33382L,33383L,33384L,33385L,33386L,33387L,33388L,33389L,33390L,
8724933391L,33392L,33393L,33394L,33395L,33396L,33397L,33398L,33399L,33400L,
8725033401L,33402L,33403L,33404L,33405L,33406L,33407L,33408L,33409L,33410L,
8725133411L,33412L,33413L,33414L,33415L,33416L,33417L,33418L,33419L,33420L,
8725233421L,33422L,33423L,33424L,33425L,33426L,33427L,33428L,33429L,33430L,
8725333431L,33432L,33433L,33434L,33435L,33436L,33437L,33438L,33439L,33440L,
8725433441L,33442L,33443L,33444L,33445L,33446L,33447L,33448L,33449L,33450L,
8725533451L,33452L,33453L,33454L,33455L,33456L,33457L,33458L,33459L,33460L,
8725633461L,33462L,33463L,33464L,33465L,33466L,33467L,33468L,33469L,33470L,
8725733471L,33472L,33473L,33474L,33475L,33476L,33477L,33478L,33479L,33480L,
8725833481L,33482L,33483L,33484L,33485L,33486L,33487L,33488L,33489L,33490L,
8725933491L,33492L,33493L,33494L,33495L,33496L,33497L,33498L,33499L,33500L,
8726033501L,33502L,33503L,33504L,33505L,33506L,33507L,33508L,33509L,33510L,
8726133511L,33512L,33513L,33514L,33515L,33516L,33517L,33518L,33519L,33520L,
8726233521L,33522L,33523L,33524L,33525L,33526L,33527L,33528L,33529L,33530L,
8726333531L,33532L,33533L,33534L,33535L,33536L,33537L,33538L,33539L,33540L,
8726433541L,33542L,33543L,33544L,33545L,33546L,33547L,33548L,33549L,33550L,
8726533551L,33552L,33553L,33554L,33555L,33556L,33557L,33558L,33559L,33560L,
8726633561L,33562L,33563L,33564L,33565L,33566L,33567L,33568L,33569L,33570L,
8726733571L,33572L,33573L,33574L,33575L,33576L,33577L,33578L,33579L,33580L,
8726833581L,33582L,33583L,33584L,33585L,33586L,33587L,33588L,33589L,33590L,
8726933591L,33592L,33593L,33594L,33595L,33596L,33597L,33598L,33599L,33600L,
8727033601L,33602L,33603L,33604L,33605L,33606L,33607L,33608L,33609L,33610L,
8727133611L,33612L,33613L,33614L,33615L,33616L,33617L,33618L,33619L,33620L,
8727233621L,33622L,33623L,33624L,33625L,33626L,33627L,33628L,33629L,33630L,
8727333631L,33632L,33633L,33634L,33635L,33636L,33637L,33638L,33639L,33640L,
8727433641L,33642L,33643L,33644L,33645L,33646L,33647L,33648L,33649L,33650L,
8727533651L,33652L,33653L,33654L,33655L,33656L,33657L,33658L,33659L,33660L,
8727633661L,33662L,33663L,33664L,33665L,33666L,33667L,33668L,33669L,33670L,
8727733671L,33672L,33673L,33674L,33675L,33676L,33677L,33678L,33679L,33680L,
8727833681L,33682L,33683L,33684L,33685L,33686L,33687L,33688L,33689L,33690L,
8727933691L,33692L,33693L,33694L,33695L,33696L,33697L,33698L,33699L,33700L,
8728033701L,33702L,33703L,33704L,33705L,33706L,33707L,33708L,33709L,33710L,
8728133711L,33712L,33713L,33714L,33715L,33716L,33717L,33718L,33719L,33720L,
8728233721L,33722L,33723L,33724L,33725L,33726L,33727L,33728L,33729L,33730L,
8728333731L,33732L,33733L,33734L,33735L,33736L,33737L,33738L,33739L,33740L,
8728433741L,33742L,33743L,33744L,33745L,33746L,33747L,33748L,33749L,33750L,
8728533751L,33752L,33753L,33754L,33755L,33756L,33757L,33758L,33759L,33760L,
8728633761L,33762L,33763L,33764L,33765L,33766L,33767L,33768L,33769L,33770L,
8728733771L,33772L,33773L,33774L,33775L,33776L,33777L,33778L,33779L,33780L,
8728833781L,33782L,33783L,33784L,33785L,33786L,33787L,33788L,33789L,33790L,
8728933791L,33792L,33793L,33794L,33795L,33796L,33797L,33798L,33799L,33800L,
8729033801L,33802L,33803L,33804L,33805L,33806L,33807L,33808L,33809L,33810L,
8729133811L,33812L,33813L,33814L,33815L,33816L,33817L,33818L,33819L,33820L,
8729233821L,33822L,33823L,33824L,33825L,33826L,33827L,33828L,33829L,33830L,
8729333831L,33832L,33833L,33834L,33835L,33836L,33837L,33838L,33839L,33840L,
8729433841L,33842L,33843L,33844L,33845L,33846L,33847L,33848L,33849L,33850L,
8729533851L,33852L,33853L,33854L,33855L,33856L,33857L,33858L,33859L,33860L,
8729633861L,33862L,33863L,33864L,33865L,33866L,33867L,33868L,33869L,33870L,
8729733871L,33872L,33873L,33874L,33875L,33876L,33877L,33878L,33879L,33880L,
8729833881L,33882L,33883L,33884L,33885L,33886L,33887L,33888L,33889L,33890L,
8729933891L,33892L,33893L,33894L,33895L,33896L,33897L,33898L,33899L,33900L,
8730033901L,33902L,33903L,33904L,33905L,33906L,33907L,33908L,33909L,33910L,
8730133911L,33912L,33913L,33914L,33915L,33916L,33917L,33918L,33919L,33920L,
8730233921L,33922L,33923L,33924L,33925L,33926L,33927L,33928L,33929L,33930L,
8730333931L,33932L,33933L,33934L,33935L,33936L,33937L,33938L,33939L,33940L,
8730433941L,33942L,33943L,33944L,33945L,33946L,33947L,33948L,33949L,33950L,
8730533951L,33952L,33953L,33954L,33955L,33956L,33957L,33958L,33959L,33960L,
8730633961L,33962L,33963L,33964L,33965L,33966L,33967L,33968L,33969L,33970L,
8730733971L,33972L,33973L,33974L,33975L,33976L,33977L,33978L,33979L,33980L,
8730833981L,33982L,33983L,33984L,33985L,33986L,33987L,33988L,33989L,33990L,
8730933991L,33992L,33993L,33994L,33995L,33996L,33997L,33998L,33999L,34000L,
8731034001L,34002L,34003L,34004L,34005L,34006L,34007L,34008L,34009L,34010L,
8731134011L,34012L,34013L,34014L,34015L,34016L,34017L,34018L,34019L,34020L,
8731234021L,34022L,34023L,34024L,34025L,34026L,34027L,34028L,34029L,34030L,
8731334031L,34032L,34033L,34034L,34035L,34036L,34037L,34038L,34039L,34040L,
8731434041L,34042L,34043L,34044L,34045L,34046L,34047L,34048L,34049L,34050L,
8731534051L,34052L,34053L,34054L,34055L,34056L,34057L,34058L,34059L,34060L,
8731634061L,34062L,34063L,34064L,34065L,34066L,34067L,34068L,34069L,34070L,
8731734071L,34072L,34073L,34074L,34075L,34076L,34077L,34078L,34079L,34080L,
8731834081L,34082L,34083L,34084L,34085L,34086L,34087L,34088L,34089L,34090L,
8731934091L,34092L,34093L,34094L,34095L,34096L,34097L,34098L,34099L,34100L,
8732034101L,34102L,34103L,34104L,34105L,34106L,34107L,34108L,34109L,34110L,
8732134111L,34112L,34113L,34114L,34115L,34116L,34117L,34118L,34119L,34120L,
8732234121L,34122L,34123L,34124L,34125L,34126L,34127L,34128L,34129L,34130L,
8732334131L,34132L,34133L,34134L,34135L,34136L,34137L,34138L,34139L,34140L,
8732434141L,34142L,34143L,34144L,34145L,34146L,34147L,34148L,34149L,34150L,
8732534151L,34152L,34153L,34154L,34155L,34156L,34157L,34158L,34159L,34160L,
8732634161L,34162L,34163L,34164L,34165L,34166L,34167L,34168L,34169L,34170L,
8732734171L,34172L,34173L,34174L,34175L,34176L,34177L,34178L,34179L,34180L,
8732834181L,34182L,34183L,34184L,34185L,34186L,34187L,34188L,34189L,34190L,
8732934191L,34192L,34193L,34194L,34195L,34196L,34197L,34198L,34199L,34200L,
8733034201L,34202L,34203L,34204L,34205L,34206L,34207L,34208L,34209L,34210L,
8733134211L,34212L,34213L,34214L,34215L,34216L,34217L,34218L,34219L,34220L,
8733234221L,34222L,34223L,34224L,34225L,34226L,34227L,34228L,34229L,34230L,
8733334231L,34232L,34233L,34234L,34235L,34236L,34237L,34238L,34239L,34240L,
8733434241L,34242L,34243L,34244L,34245L,34246L,34247L,34248L,34249L,34250L,
8733534251L,34252L,34253L,34254L,34255L,34256L,34257L,34258L,34259L,34260L,
8733634261L,34262L,34263L,34264L,34265L,34266L,34267L,34268L,34269L,34270L,
8733734271L,34272L,34273L,34274L,34275L,34276L,34277L,34278L,34279L,34280L,
8733834281L,34282L,34283L,34284L,34285L,34286L,34287L,34288L,34289L,34290L,
8733934291L,34292L,34293L,34294L,34295L,34296L,34297L,34298L,34299L,34300L,
8734034301L,34302L,34303L,34304L,34305L,34306L,34307L,34308L,34309L,34310L,
8734134311L,34312L,34313L,34314L,34315L,34316L,34317L,34318L,34319L,34320L,
8734234321L,34322L,34323L,34324L,34325L,34326L,34327L,34328L,34329L,34330L,
8734334331L,34332L,34333L,34334L,34335L,34336L,34337L,34338L,34339L,34340L,
8734434341L,34342L,34343L,34344L,34345L,34346L,34347L,34348L,34349L,34350L,
8734534351L,34352L,34353L,34354L,34355L,34356L,34357L,34358L,34359L,34360L,
8734634361L,34362L,34363L,34364L,34365L,34366L,34367L,34368L,34369L,34370L,
8734734371L,34372L,34373L,34374L,34375L,34376L,34377L,34378L,34379L,34380L,
8734834381L,34382L,34383L,34384L,34385L,34386L,34387L,34388L,34389L,34390L,
8734934391L,34392L,34393L,34394L,34395L,34396L,34397L,34398L,34399L,34400L,
8735034401L,34402L,34403L,34404L,34405L,34406L,34407L,34408L,34409L,34410L,
8735134411L,34412L,34413L,34414L,34415L,34416L,34417L,34418L,34419L,34420L,
8735234421L,34422L,34423L,34424L,34425L,34426L,34427L,34428L,34429L,34430L,
8735334431L,34432L,34433L,34434L,34435L,34436L,34437L,34438L,34439L,34440L,
8735434441L,34442L,34443L,34444L,34445L,34446L,34447L,34448L,34449L,34450L,
8735534451L,34452L,34453L,34454L,34455L,34456L,34457L,34458L,34459L,34460L,
8735634461L,34462L,34463L,34464L,34465L,34466L,34467L,34468L,34469L,34470L,
8735734471L,34472L,34473L,34474L,34475L,34476L,34477L,34478L,34479L,34480L,
8735834481L,34482L,34483L,34484L,34485L,34486L,34487L,34488L,34489L,34490L,
8735934491L,34492L,34493L,34494L,34495L,34496L,34497L,34498L,34499L,34500L,
8736034501L,34502L,34503L,34504L,34505L,34506L,34507L,34508L,34509L,34510L,
8736134511L,34512L,34513L,34514L,34515L,34516L,34517L,34518L,34519L,34520L,
8736234521L,34522L,34523L,34524L,34525L,34526L,34527L,34528L,34529L,34530L,
8736334531L,34532L,34533L,34534L,34535L,34536L,34537L,34538L,34539L,34540L,
8736434541L,34542L,34543L,34544L,34545L,34546L,34547L,34548L,34549L,34550L,
8736534551L,34552L,34553L,34554L,34555L,34556L,34557L,34558L,34559L,34560L,
8736634561L,34562L,34563L,34564L,34565L,34566L,34567L,34568L,34569L,34570L,
8736734571L,34572L,34573L,34574L,34575L,34576L,34577L,34578L,34579L,34580L,
8736834581L,34582L,34583L,34584L,34585L,34586L,34587L,34588L,34589L,34590L,
8736934591L,34592L,34593L,34594L,34595L,34596L,34597L,34598L,34599L,34600L,
8737034601L,34602L,34603L,34604L,34605L,34606L,34607L,34608L,34609L,34610L,
8737134611L,34612L,34613L,34614L,34615L,34616L,34617L,34618L,34619L,34620L,
8737234621L,34622L,34623L,34624L,34625L,34626L,34627L,34628L,34629L,34630L,
8737334631L,34632L,34633L,34634L,34635L,34636L,34637L,34638L,34639L,34640L,
8737434641L,34642L,34643L,34644L,34645L,34646L,34647L,34648L,34649L,34650L,
8737534651L,34652L,34653L,34654L,34655L,34656L,34657L,34658L,34659L,34660L,
8737634661L,34662L,34663L,34664L,34665L,34666L,34667L,34668L,34669L,34670L,
8737734671L,34672L,34673L,34674L,34675L,34676L,34677L,34678L,34679L,34680L,
8737834681L,34682L,34683L,34684L,34685L,34686L,34687L,34688L,34689L,34690L,
8737934691L,34692L,34693L,34694L,34695L,34696L,34697L,34698L,34699L,34700L,
8738034701L,34702L,34703L,34704L,34705L,34706L,34707L,34708L,34709L,34710L,
8738134711L,34712L,34713L,34714L,34715L,34716L,34717L,34718L,34719L,34720L,
8738234721L,34722L,34723L,34724L,34725L,34726L,34727L,34728L,34729L,34730L,
8738334731L,34732L,34733L,34734L,34735L,34736L,34737L,34738L,34739L,34740L,
8738434741L,34742L,34743L,34744L,34745L,34746L,34747L,34748L,34749L,34750L,
8738534751L,34752L,34753L,34754L,34755L,34756L,34757L,34758L,34759L,34760L,
8738634761L,34762L,34763L,34764L,34765L,34766L,34767L,34768L,34769L,34770L,
8738734771L,34772L,34773L,34774L,34775L,34776L,34777L,34778L,34779L,34780L,
8738834781L,34782L,34783L,34784L,34785L,34786L,34787L,34788L,34789L,34790L,
8738934791L,34792L,34793L,34794L,34795L,34796L,34797L,34798L,34799L,34800L,
8739034801L,34802L,34803L,34804L,34805L,34806L,34807L,34808L,34809L,34810L,
8739134811L,34812L,34813L,34814L,34815L,34816L,34817L,34818L,34819L,34820L,
8739234821L,34822L,34823L,34824L,34825L,34826L,34827L,34828L,34829L,34830L,
8739334831L,34832L,34833L,34834L,34835L,34836L,34837L,34838L,34839L,34840L,
8739434841L,34842L,34843L,34844L,34845L,34846L,34847L,34848L,34849L,34850L,
8739534851L,34852L,34853L,34854L,34855L,34856L,34857L,34858L,34859L,34860L,
8739634861L,34862L,34863L,34864L,34865L,34866L,34867L,34868L,34869L,34870L,
8739734871L,34872L,34873L,34874L,34875L,34876L,34877L,34878L,34879L,34880L,
8739834881L,34882L,34883L,34884L,34885L,34886L,34887L,34888L,34889L,34890L,
8739934891L,34892L,34893L,34894L,34895L,34896L,34897L,34898L,34899L,34900L,
8740034901L,34902L,34903L,34904L,34905L,34906L,34907L,34908L,34909L,34910L,
8740134911L,34912L,34913L,34914L,34915L,34916L,34917L,34918L,34919L,34920L,
8740234921L,34922L,34923L,34924L,34925L,34926L,34927L,34928L,34929L,34930L,
8740334931L,34932L,34933L,34934L,34935L,34936L,34937L,34938L,34939L,34940L,
8740434941L,34942L,34943L,34944L,34945L,34946L,34947L,34948L,34949L,34950L,
8740534951L,34952L,34953L,34954L,34955L,34956L,34957L,34958L,34959L,34960L,
8740634961L,34962L,34963L,34964L,34965L,34966L,34967L,34968L,34969L,34970L,
8740734971L,34972L,34973L,34974L,34975L,34976L,34977L,34978L,34979L,34980L,
8740834981L,34982L,34983L,34984L,34985L,34986L,34987L,34988L,34989L,34990L,
8740934991L,34992L,34993L,34994L,34995L,34996L,34997L,34998L,34999L,35000L,
8741035001L,35002L,35003L,35004L,35005L,35006L,35007L,35008L,35009L,35010L,
8741135011L,35012L,35013L,35014L,35015L,35016L,35017L,35018L,35019L,35020L,
8741235021L,35022L,35023L,35024L,35025L,35026L,35027L,35028L,35029L,35030L,
8741335031L,35032L,35033L,35034L,35035L,35036L,35037L,35038L,35039L,35040L,
8741435041L,35042L,35043L,35044L,35045L,35046L,35047L,35048L,35049L,35050L,
8741535051L,35052L,35053L,35054L,35055L,35056L,35057L,35058L,35059L,35060L,
8741635061L,35062L,35063L,35064L,35065L,35066L,35067L,35068L,35069L,35070L,
8741735071L,35072L,35073L,35074L,35075L,35076L,35077L,35078L,35079L,35080L,
8741835081L,35082L,35083L,35084L,35085L,35086L,35087L,35088L,35089L,35090L,
8741935091L,35092L,35093L,35094L,35095L,35096L,35097L,35098L,35099L,35100L,
8742035101L,35102L,35103L,35104L,35105L,35106L,35107L,35108L,35109L,35110L,
8742135111L,35112L,35113L,35114L,35115L,35116L,35117L,35118L,35119L,35120L,
8742235121L,35122L,35123L,35124L,35125L,35126L,35127L,35128L,35129L,35130L,
8742335131L,35132L,35133L,35134L,35135L,35136L,35137L,35138L,35139L,35140L,
8742435141L,35142L,35143L,35144L,35145L,35146L,35147L,35148L,35149L,35150L,
8742535151L,35152L,35153L,35154L,35155L,35156L,35157L,35158L,35159L,35160L,
8742635161L,35162L,35163L,35164L,35165L,35166L,35167L,35168L,35169L,35170L,
8742735171L,35172L,35173L,35174L,35175L,35176L,35177L,35178L,35179L,35180L,
8742835181L,35182L,35183L,35184L,35185L,35186L,35187L,35188L,35189L,35190L,
8742935191L,35192L,35193L,35194L,35195L,35196L,35197L,35198L,35199L,35200L,
8743035201L,35202L,35203L,35204L,35205L,35206L,35207L,35208L,35209L,35210L,
8743135211L,35212L,35213L,35214L,35215L,35216L,35217L,35218L,35219L,35220L,
8743235221L,35222L,35223L,35224L,35225L,35226L,35227L,35228L,35229L,35230L,
8743335231L,35232L,35233L,35234L,35235L,35236L,35237L,35238L,35239L,35240L,
8743435241L,35242L,35243L,35244L,35245L,35246L,35247L,35248L,35249L,35250L,
8743535251L,35252L,35253L,35254L,35255L,35256L,35257L,35258L,35259L,35260L,
8743635261L,35262L,35263L,35264L,35265L,35266L,35267L,35268L,35269L,35270L,
8743735271L,35272L,35273L,35274L,35275L,35276L,35277L,35278L,35279L,35280L,
8743835281L,35282L,35283L,35284L,35285L,35286L,35287L,35288L,35289L,35290L,
8743935291L,35292L,35293L,35294L,35295L,35296L,35297L,35298L,35299L,35300L,
8744035301L,35302L,35303L,35304L,35305L,35306L,35307L,35308L,35309L,35310L,
8744135311L,35312L,35313L,35314L,35315L,35316L,35317L,35318L,35319L,35320L,
8744235321L,35322L,35323L,35324L,35325L,35326L,35327L,35328L,35329L,35330L,
8744335331L,35332L,35333L,35334L,35335L,35336L,35337L,35338L,35339L,35340L,
8744435341L,35342L,35343L,35344L,35345L,35346L,35347L,35348L,35349L,35350L,
8744535351L,35352L,35353L,35354L,35355L,35356L,35357L,35358L,35359L,35360L,
8744635361L,35362L,35363L,35364L,35365L,35366L,35367L,35368L,35369L,35370L,
8744735371L,35372L,35373L,35374L,35375L,35376L,35377L,35378L,35379L,35380L,
8744835381L,35382L,35383L,35384L,35385L,35386L,35387L,35388L,35389L,35390L,
8744935391L,35392L,35393L,35394L,35395L,35396L,35397L,35398L,35399L,35400L,
8745035401L,35402L,35403L,35404L,35405L,35406L,35407L,35408L,35409L,35410L,
8745135411L,35412L,35413L,35414L,35415L,35416L,35417L,35418L,35419L,35420L,
8745235421L,35422L,35423L,35424L,35425L,35426L,35427L,35428L,35429L,35430L,
8745335431L,35432L,35433L,35434L,35435L,35436L,35437L,35438L,35439L,35440L,
8745435441L,35442L,35443L,35444L,35445L,35446L,35447L,35448L,35449L,35450L,
8745535451L,35452L,35453L,35454L,35455L,35456L,35457L,35458L,35459L,35460L,
8745635461L,35462L,35463L,35464L,35465L,35466L,35467L,35468L,35469L,35470L,
8745735471L,35472L,35473L,35474L,35475L,35476L,35477L,35478L,35479L,35480L,
8745835481L,35482L,35483L,35484L,35485L,35486L,35487L,35488L,35489L,35490L,
8745935491L,35492L,35493L,35494L,35495L,35496L,35497L,35498L,35499L,35500L,
8746035501L,35502L,35503L,35504L,35505L,35506L,35507L,35508L,35509L,35510L,
8746135511L,35512L,35513L,35514L,35515L,35516L,35517L,35518L,35519L,35520L,
8746235521L,35522L,35523L,35524L,35525L,35526L,35527L,35528L,35529L,35530L,
8746335531L,35532L,35533L,35534L,35535L,35536L,35537L,35538L,35539L,35540L,
8746435541L,35542L,35543L,35544L,35545L,35546L,35547L,35548L,35549L,35550L,
8746535551L,35552L,35553L,35554L,35555L,35556L,35557L,35558L,35559L,35560L,
8746635561L,35562L,35563L,35564L,35565L,35566L,35567L,35568L,35569L,35570L,
8746735571L,35572L,35573L,35574L,35575L,35576L,35577L,35578L,35579L,35580L,
8746835581L,35582L,35583L,35584L,35585L,35586L,35587L,35588L,35589L,35590L,
8746935591L,35592L,35593L,35594L,35595L,35596L,35597L,35598L,35599L,35600L,
8747035601L,35602L,35603L,35604L,35605L,35606L,35607L,35608L,35609L,35610L,
8747135611L,35612L,35613L,35614L,35615L,35616L,35617L,35618L,35619L,35620L,
8747235621L,35622L,35623L,35624L,35625L,35626L,35627L,35628L,35629L,35630L,
8747335631L,35632L,35633L,35634L,35635L,35636L,35637L,35638L,35639L,35640L,
8747435641L,35642L,35643L,35644L,35645L,35646L,35647L,35648L,35649L,35650L,
8747535651L,35652L,35653L,35654L,35655L,35656L,35657L,35658L,35659L,35660L,
8747635661L,35662L,35663L,35664L,35665L,35666L,35667L,35668L,35669L,35670L,
8747735671L,35672L,35673L,35674L,35675L,35676L,35677L,35678L,35679L,35680L,
8747835681L,35682L,35683L,35684L,35685L,35686L,35687L,35688L,35689L,35690L,
8747935691L,35692L,35693L,35694L,35695L,35696L,35697L,35698L,35699L,35700L,
8748035701L,35702L,35703L,35704L,35705L,35706L,35707L,35708L,35709L,35710L,
8748135711L,35712L,35713L,35714L,35715L,35716L,35717L,35718L,35719L,35720L,
8748235721L,35722L,35723L,35724L,35725L,35726L,35727L,35728L,35729L,35730L,
8748335731L,35732L,35733L,35734L,35735L,35736L,35737L,35738L,35739L,35740L,
8748435741L,35742L,35743L,35744L,35745L,35746L,35747L,35748L,35749L,35750L,
8748535751L,35752L,35753L,35754L,35755L,35756L,35757L,35758L,35759L,35760L,
8748635761L,35762L,35763L,35764L,35765L,35766L,35767L,35768L,35769L,35770L,
8748735771L,35772L,35773L,35774L,35775L,35776L,35777L,35778L,35779L,35780L,
8748835781L,35782L,35783L,35784L,35785L,35786L,35787L,35788L,35789L,35790L,
8748935791L,35792L,35793L,35794L,35795L,35796L,35797L,35798L,35799L,35800L,
8749035801L,35802L,35803L,35804L,35805L,35806L,35807L,35808L,35809L,35810L,
8749135811L,35812L,35813L,35814L,35815L,35816L,35817L,35818L,35819L,35820L,
8749235821L,35822L,35823L,35824L,35825L,35826L,35827L,35828L,35829L,35830L,
8749335831L,35832L,35833L,35834L,35835L,35836L,35837L,35838L,35839L,35840L,
8749435841L,35842L,35843L,35844L,35845L,35846L,35847L,35848L,35849L,35850L,
8749535851L,35852L,35853L,35854L,35855L,35856L,35857L,35858L,35859L,35860L,
8749635861L,35862L,35863L,35864L,35865L,35866L,35867L,35868L,35869L,35870L,
8749735871L,35872L,35873L,35874L,35875L,35876L,35877L,35878L,35879L,35880L,
8749835881L,35882L,35883L,35884L,35885L,35886L,35887L,35888L,35889L,35890L,
8749935891L,35892L,35893L,35894L,35895L,35896L,35897L,35898L,35899L,35900L,
8750035901L,35902L,35903L,35904L,35905L,35906L,35907L,35908L,35909L,35910L,
8750135911L,35912L,35913L,35914L,35915L,35916L,35917L,35918L,35919L,35920L,
8750235921L,35922L,35923L,35924L,35925L,35926L,35927L,35928L,35929L,35930L,
8750335931L,35932L,35933L,35934L,35935L,35936L,35937L,35938L,35939L,35940L,
8750435941L,35942L,35943L,35944L,35945L,35946L,35947L,35948L,35949L,35950L,
8750535951L,35952L,35953L,35954L,35955L,35956L,35957L,35958L,35959L,35960L,
8750635961L,35962L,35963L,35964L,35965L,35966L,35967L,35968L,35969L,35970L,
8750735971L,35972L,35973L,35974L,35975L,35976L,35977L,35978L,35979L,35980L,
8750835981L,35982L,35983L,35984L,35985L,35986L,35987L,35988L,35989L,35990L,
8750935991L,35992L,35993L,35994L,35995L,35996L,35997L,35998L,35999L,36000L,
8751036001L,36002L,36003L,36004L,36005L,36006L,36007L,36008L,36009L,36010L,
8751136011L,36012L,36013L,36014L,36015L,36016L,36017L,36018L,36019L,36020L,
8751236021L,36022L,36023L,36024L,36025L,36026L,36027L,36028L,36029L,36030L,
8751336031L,36032L,36033L,36034L,36035L,36036L,36037L,36038L,36039L,36040L,
8751436041L,36042L,36043L,36044L,36045L,36046L,36047L,36048L,36049L,36050L,
8751536051L,36052L,36053L,36054L,36055L,36056L,36057L,36058L,36059L,36060L,
8751636061L,36062L,36063L,36064L,36065L,36066L,36067L,36068L,36069L,36070L,
8751736071L,36072L,36073L,36074L,36075L,36076L,36077L,36078L,36079L,36080L,
8751836081L,36082L,36083L,36084L,36085L,36086L,36087L,36088L,36089L,36090L,
8751936091L,36092L,36093L,36094L,36095L,36096L,36097L,36098L,36099L,36100L,
8752036101L,36102L,36103L,36104L,36105L,36106L,36107L,36108L,36109L,36110L,
8752136111L,36112L,36113L,36114L,36115L,36116L,36117L,36118L,36119L,36120L,
8752236121L,36122L,36123L,36124L,36125L,36126L,36127L,36128L,36129L,36130L,
8752336131L,36132L,36133L,36134L,36135L,36136L,36137L,36138L,36139L,36140L,
8752436141L,36142L,36143L,36144L,36145L,36146L,36147L,36148L,36149L,36150L,
8752536151L,36152L,36153L,36154L,36155L,36156L,36157L,36158L,36159L,36160L,
8752636161L,36162L,36163L,36164L,36165L,36166L,36167L,36168L,36169L,36170L,
8752736171L,36172L,36173L,36174L,36175L,36176L,36177L,36178L,36179L,36180L,
8752836181L,36182L,36183L,36184L,36185L,36186L,36187L,36188L,36189L,36190L,
8752936191L,36192L,36193L,36194L,36195L,36196L,36197L,36198L,36199L,36200L,
8753036201L,36202L,36203L,36204L,36205L,36206L,36207L,36208L,36209L,36210L,
8753136211L,36212L,36213L,36214L,36215L,36216L,36217L,36218L,36219L,36220L,
8753236221L,36222L,36223L,36224L,36225L,36226L,36227L,36228L,36229L,36230L,
8753336231L,36232L,36233L,36234L,36235L,36236L,36237L,36238L,36239L,36240L,
8753436241L,36242L,36243L,36244L,36245L,36246L,36247L,36248L,36249L,36250L,
8753536251L,36252L,36253L,36254L,36255L,36256L,36257L,36258L,36259L,36260L,
8753636261L,36262L,36263L,36264L,36265L,36266L,36267L,36268L,36269L,36270L,
8753736271L,36272L,36273L,36274L,36275L,36276L,36277L,36278L,36279L,36280L,
8753836281L,36282L,36283L,36284L,36285L,36286L,36287L,36288L,36289L,36290L,
8753936291L,36292L,36293L,36294L,36295L,36296L,36297L,36298L,36299L,36300L,
8754036301L,36302L,36303L,36304L,36305L,36306L,36307L,36308L,36309L,36310L,
8754136311L,36312L,36313L,36314L,36315L,36316L,36317L,36318L,36319L,36320L,
8754236321L,36322L,36323L,36324L,36325L,36326L,36327L,36328L,36329L,36330L,
8754336331L,36332L,36333L,36334L,36335L,36336L,36337L,36338L,36339L,36340L,
8754436341L,36342L,36343L,36344L,36345L,36346L,36347L,36348L,36349L,36350L,
8754536351L,36352L,36353L,36354L,36355L,36356L,36357L,36358L,36359L,36360L,
8754636361L,36362L,36363L,36364L,36365L,36366L,36367L,36368L,36369L,36370L,
8754736371L,36372L,36373L,36374L,36375L,36376L,36377L,36378L,36379L,36380L,
8754836381L,36382L,36383L,36384L,36385L,36386L,36387L,36388L,36389L,36390L,
8754936391L,36392L,36393L,36394L,36395L,36396L,36397L,36398L,36399L,36400L,
8755036401L,36402L,36403L,36404L,36405L,36406L,36407L,36408L,36409L,36410L,
8755136411L,36412L,36413L,36414L,36415L,36416L,36417L,36418L,36419L,36420L,
8755236421L,36422L,36423L,36424L,36425L,36426L,36427L,36428L,36429L,36430L,
8755336431L,36432L,36433L,36434L,36435L,36436L,36437L,36438L,36439L,36440L,
8755436441L,36442L,36443L,36444L,36445L,36446L,36447L,36448L,36449L,36450L,
8755536451L,36452L,36453L,36454L,36455L,36456L,36457L,36458L,36459L,36460L,
8755636461L,36462L,36463L,36464L,36465L,36466L,36467L,36468L,36469L,36470L,
8755736471L,36472L,36473L,36474L,36475L,36476L,36477L,36478L,36479L,36480L,
8755836481L,36482L,36483L,36484L,36485L,36486L,36487L,36488L,36489L,36490L,
8755936491L,36492L,36493L,36494L,36495L,36496L,36497L,36498L,36499L,36500L,
8756036501L,36502L,36503L,36504L,36505L,36506L,36507L,36508L,36509L,36510L,
8756136511L,36512L,36513L,36514L,36515L,36516L,36517L,36518L,36519L,36520L,
8756236521L,36522L,36523L,36524L,36525L,36526L,36527L,36528L,36529L,36530L,
8756336531L,36532L,36533L,36534L,36535L,36536L,36537L,36538L,36539L,36540L,
8756436541L,36542L,36543L,36544L,36545L,36546L,36547L,36548L,36549L,36550L,
8756536551L,36552L,36553L,36554L,36555L,36556L,36557L,36558L,36559L,36560L,
8756636561L,36562L,36563L,36564L,36565L,36566L,36567L,36568L,36569L,36570L,
8756736571L,36572L,36573L,36574L,36575L,36576L,36577L,36578L,36579L,36580L,
8756836581L,36582L,36583L,36584L,36585L,36586L,36587L,36588L,36589L,36590L,
8756936591L,36592L,36593L,36594L,36595L,36596L,36597L,36598L,36599L,36600L,
8757036601L,36602L,36603L,36604L,36605L,36606L,36607L,36608L,36609L,36610L,
8757136611L,36612L,36613L,36614L,36615L,36616L,36617L,36618L,36619L,36620L,
8757236621L,36622L,36623L,36624L,36625L,36626L,36627L,36628L,36629L,36630L,
8757336631L,36632L,36633L,36634L,36635L,36636L,36637L,36638L,36639L,36640L,
8757436641L,36642L,36643L,36644L,36645L,36646L,36647L,36648L,36649L,36650L,
8757536651L,36652L,36653L,36654L,36655L,36656L,36657L,36658L,36659L,36660L,
8757636661L,36662L,36663L,36664L,36665L,36666L,36667L,36668L,36669L,36670L,
8757736671L,36672L,36673L,36674L,36675L,36676L,36677L,36678L,36679L,36680L,
8757836681L,36682L,36683L,36684L,36685L,36686L,36687L,36688L,36689L,36690L,
8757936691L,36692L,36693L,36694L,36695L,36696L,36697L,36698L,36699L,36700L,
8758036701L,36702L,36703L,36704L,36705L,36706L,36707L,36708L,36709L,36710L,
8758136711L,36712L,36713L,36714L,36715L,36716L,36717L,36718L,36719L,36720L,
8758236721L,36722L,36723L,36724L,36725L,36726L,36727L,36728L,36729L,36730L,
8758336731L,36732L,36733L,36734L,36735L,36736L,36737L,36738L,36739L,36740L,
8758436741L,36742L,36743L,36744L,36745L,36746L,36747L,36748L,36749L,36750L,
8758536751L,36752L,36753L,36754L,36755L,36756L,36757L,36758L,36759L,36760L,
8758636761L,36762L,36763L,36764L,36765L,36766L,36767L,36768L,36769L,36770L,
8758736771L,36772L,36773L,36774L,36775L,36776L,36777L,36778L,36779L,36780L,
8758836781L,36782L,36783L,36784L,36785L,36786L,36787L,36788L,36789L,36790L,
8758936791L,36792L,36793L,36794L,36795L,36796L,36797L,36798L,36799L,36800L,
8759036801L,36802L,36803L,36804L,36805L,36806L,36807L,36808L,36809L,36810L,
8759136811L,36812L,36813L,36814L,36815L,36816L,36817L,36818L,36819L,36820L,
8759236821L,36822L,36823L,36824L,36825L,36826L,36827L,36828L,36829L,36830L,
8759336831L,36832L,36833L,36834L,36835L,36836L,36837L,36838L,36839L,36840L,
8759436841L,36842L,36843L,36844L,36845L,36846L,36847L,36848L,36849L,36850L,
8759536851L,36852L,36853L,36854L,36855L,36856L,36857L,36858L,36859L,36860L,
8759636861L,36862L,36863L,36864L,36865L,36866L,36867L,36868L,36869L,36870L,
8759736871L,36872L,36873L,36874L,36875L,36876L,36877L,36878L,36879L,36880L,
8759836881L,36882L,36883L,36884L,36885L,36886L,36887L,36888L,36889L,36890L,
8759936891L,36892L,36893L,36894L,36895L,36896L,36897L,36898L,36899L,36900L,
8760036901L,36902L,36903L,36904L,36905L,36906L,36907L,36908L,36909L,36910L,
8760136911L,36912L,36913L,36914L,36915L,36916L,36917L,36918L,36919L,36920L,
8760236921L,36922L,36923L,36924L,36925L,36926L,36927L,36928L,36929L,36930L,
8760336931L,36932L,36933L,36934L,36935L,36936L,36937L,36938L,36939L,36940L,
8760436941L,36942L,36943L,36944L,36945L,36946L,36947L,36948L,36949L,36950L,
8760536951L,36952L,36953L,36954L,36955L,36956L,36957L,36958L,36959L,36960L,
8760636961L,36962L,36963L,36964L,36965L,36966L,36967L,36968L,36969L,36970L,
8760736971L,36972L,36973L,36974L,36975L,36976L,36977L,36978L,36979L,36980L,
8760836981L,36982L,36983L,36984L,36985L,36986L,36987L,36988L,36989L,36990L,
8760936991L,36992L,36993L,36994L,36995L,36996L,36997L,36998L,36999L,37000L,
8761037001L,37002L,37003L,37004L,37005L,37006L,37007L,37008L,37009L,37010L,
8761137011L,37012L,37013L,37014L,37015L,37016L,37017L,37018L,37019L,37020L,
8761237021L,37022L,37023L,37024L,37025L,37026L,37027L,37028L,37029L,37030L,
8761337031L,37032L,37033L,37034L,37035L,37036L,37037L,37038L,37039L,37040L,
8761437041L,37042L,37043L,37044L,37045L,37046L,37047L,37048L,37049L,37050L,
8761537051L,37052L,37053L,37054L,37055L,37056L,37057L,37058L,37059L,37060L,
8761637061L,37062L,37063L,37064L,37065L,37066L,37067L,37068L,37069L,37070L,
8761737071L,37072L,37073L,37074L,37075L,37076L,37077L,37078L,37079L,37080L,
8761837081L,37082L,37083L,37084L,37085L,37086L,37087L,37088L,37089L,37090L,
8761937091L,37092L,37093L,37094L,37095L,37096L,37097L,37098L,37099L,37100L,
8762037101L,37102L,37103L,37104L,37105L,37106L,37107L,37108L,37109L,37110L,
8762137111L,37112L,37113L,37114L,37115L,37116L,37117L,37118L,37119L,37120L,
8762237121L,37122L,37123L,37124L,37125L,37126L,37127L,37128L,37129L,37130L,
8762337131L,37132L,37133L,37134L,37135L,37136L,37137L,37138L,37139L,37140L,
8762437141L,37142L,37143L,37144L,37145L,37146L,37147L,37148L,37149L,37150L,
8762537151L,37152L,37153L,37154L,37155L,37156L,37157L,37158L,37159L,37160L,
8762637161L,37162L,37163L,37164L,37165L,37166L,37167L,37168L,37169L,37170L,
8762737171L,37172L,37173L,37174L,37175L,37176L,37177L,37178L,37179L,37180L,
8762837181L,37182L,37183L,37184L,37185L,37186L,37187L,37188L,37189L,37190L,
8762937191L,37192L,37193L,37194L,37195L,37196L,37197L,37198L,37199L,37200L,
8763037201L,37202L,37203L,37204L,37205L,37206L,37207L,37208L,37209L,37210L,
8763137211L,37212L,37213L,37214L,37215L,37216L,37217L,37218L,37219L,37220L,
8763237221L,37222L,37223L,37224L,37225L,37226L,37227L,37228L,37229L,37230L,
8763337231L,37232L,37233L,37234L,37235L,37236L,37237L,37238L,37239L,37240L,
8763437241L,37242L,37243L,37244L,37245L,37246L,37247L,37248L,37249L,37250L,
8763537251L,37252L,37253L,37254L,37255L,37256L,37257L,37258L,37259L,37260L,
8763637261L,37262L,37263L,37264L,37265L,37266L,37267L,37268L,37269L,37270L,
8763737271L,37272L,37273L,37274L,37275L,37276L,37277L,37278L,37279L,37280L,
8763837281L,37282L,37283L,37284L,37285L,37286L,37287L,37288L,37289L,37290L,
8763937291L,37292L,37293L,37294L,37295L,37296L,37297L,37298L,37299L,37300L,
8764037301L,37302L,37303L,37304L,37305L,37306L,37307L,37308L,37309L,37310L,
8764137311L,37312L,37313L,37314L,37315L,37316L,37317L,37318L,37319L,37320L,
8764237321L,37322L,37323L,37324L,37325L,37326L,37327L,37328L,37329L,37330L,
8764337331L,37332L,37333L,37334L,37335L,37336L,37337L,37338L,37339L,37340L,
8764437341L,37342L,37343L,37344L,37345L,37346L,37347L,37348L,37349L,37350L,
8764537351L,37352L,37353L,37354L,37355L,37356L,37357L,37358L,37359L,37360L,
8764637361L,37362L,37363L,37364L,37365L,37366L,37367L,37368L,37369L,37370L,
8764737371L,37372L,37373L,37374L,37375L,37376L,37377L,37378L,37379L,37380L,
8764837381L,37382L,37383L,37384L,37385L,37386L,37387L,37388L,37389L,37390L,
8764937391L,37392L,37393L,37394L,37395L,37396L,37397L,37398L,37399L,37400L,
8765037401L,37402L,37403L,37404L,37405L,37406L,37407L,37408L,37409L,37410L,
8765137411L,37412L,37413L,37414L,37415L,37416L,37417L,37418L,37419L,37420L,
8765237421L,37422L,37423L,37424L,37425L,37426L,37427L,37428L,37429L,37430L,
8765337431L,37432L,37433L,37434L,37435L,37436L,37437L,37438L,37439L,37440L,
8765437441L,37442L,37443L,37444L,37445L,37446L,37447L,37448L,37449L,37450L,
8765537451L,37452L,37453L,37454L,37455L,37456L,37457L,37458L,37459L,37460L,
8765637461L,37462L,37463L,37464L,37465L,37466L,37467L,37468L,37469L,37470L,
8765737471L,37472L,37473L,37474L,37475L,37476L,37477L,37478L,37479L,37480L,
8765837481L,37482L,37483L,37484L,37485L,37486L,37487L,37488L,37489L,37490L,
8765937491L,37492L,37493L,37494L,37495L,37496L,37497L,37498L,37499L,37500L,
8766037501L,37502L,37503L,37504L,37505L,37506L,37507L,37508L,37509L,37510L,
8766137511L,37512L,37513L,37514L,37515L,37516L,37517L,37518L,37519L,37520L,
8766237521L,37522L,37523L,37524L,37525L,37526L,37527L,37528L,37529L,37530L,
8766337531L,37532L,37533L,37534L,37535L,37536L,37537L,37538L,37539L,37540L,
8766437541L,37542L,37543L,37544L,37545L,37546L,37547L,37548L,37549L,37550L,
8766537551L,37552L,37553L,37554L,37555L,37556L,37557L,37558L,37559L,37560L,
8766637561L,37562L,37563L,37564L,37565L,37566L,37567L,37568L,37569L,37570L,
8766737571L,37572L,37573L,37574L,37575L,37576L,37577L,37578L,37579L,37580L,
8766837581L,37582L,37583L,37584L,37585L,37586L,37587L,37588L,37589L,37590L,
8766937591L,37592L,37593L,37594L,37595L,37596L,37597L,37598L,37599L,37600L,
8767037601L,37602L,37603L,37604L,37605L,37606L,37607L,37608L,37609L,37610L,
8767137611L,37612L,37613L,37614L,37615L,37616L,37617L,37618L,37619L,37620L,
8767237621L,37622L,37623L,37624L,37625L,37626L,37627L,37628L,37629L,37630L,
8767337631L,37632L,37633L,37634L,37635L,37636L,37637L,37638L,37639L,37640L,
8767437641L,37642L,37643L,37644L,37645L,37646L,37647L,37648L,37649L,37650L,
8767537651L,37652L,37653L,37654L,37655L,37656L,37657L,37658L,37659L,37660L,
8767637661L,37662L,37663L,37664L,37665L,37666L,37667L,37668L,37669L,37670L,
8767737671L,37672L,37673L,37674L,37675L,37676L,37677L,37678L,37679L,37680L,
8767837681L,37682L,37683L,37684L,37685L,37686L,37687L,37688L,37689L,37690L,
8767937691L,37692L,37693L,37694L,37695L,37696L,37697L,37698L,37699L,37700L,
8768037701L,37702L,37703L,37704L,37705L,37706L,37707L,37708L,37709L,37710L,
8768137711L,37712L,37713L,37714L,37715L,37716L,37717L,37718L,37719L,37720L,
8768237721L,37722L,37723L,37724L,37725L,37726L,37727L,37728L,37729L,37730L,
8768337731L,37732L,37733L,37734L,37735L,37736L,37737L,37738L,37739L,37740L,
8768437741L,37742L,37743L,37744L,37745L,37746L,37747L,37748L,37749L,37750L,
8768537751L,37752L,37753L,37754L,37755L,37756L,37757L,37758L,37759L,37760L,
8768637761L,37762L,37763L,37764L,37765L,37766L,37767L,37768L,37769L,37770L,
8768737771L,37772L,37773L,37774L,37775L,37776L,37777L,37778L,37779L,37780L,
8768837781L,37782L,37783L,37784L,37785L,37786L,37787L,37788L,37789L,37790L,
8768937791L,37792L,37793L,37794L,37795L,37796L,37797L,37798L,37799L,37800L,
8769037801L,37802L,37803L,37804L,37805L,37806L,37807L,37808L,37809L,37810L,
8769137811L,37812L,37813L,37814L,37815L,37816L,37817L,37818L,37819L,37820L,
8769237821L,37822L,37823L,37824L,37825L,37826L,37827L,37828L,37829L,37830L,
8769337831L,37832L,37833L,37834L,37835L,37836L,37837L,37838L,37839L,37840L,
8769437841L,37842L,37843L,37844L,37845L,37846L,37847L,37848L,37849L,37850L,
8769537851L,37852L,37853L,37854L,37855L,37856L,37857L,37858L,37859L,37860L,
8769637861L,37862L,37863L,37864L,37865L,37866L,37867L,37868L,37869L,37870L,
8769737871L,37872L,37873L,37874L,37875L,37876L,37877L,37878L,37879L,37880L,
8769837881L,37882L,37883L,37884L,37885L,37886L,37887L,37888L,37889L,37890L,
8769937891L,37892L,37893L,37894L,37895L,37896L,37897L,37898L,37899L,37900L,
8770037901L,37902L,37903L,37904L,37905L,37906L,37907L,37908L,37909L,37910L,
8770137911L,37912L,37913L,37914L,37915L,37916L,37917L,37918L,37919L,37920L,
8770237921L,37922L,37923L,37924L,37925L,37926L,37927L,37928L,37929L,37930L,
8770337931L,37932L,37933L,37934L,37935L,37936L,37937L,37938L,37939L,37940L,
8770437941L,37942L,37943L,37944L,37945L,37946L,37947L,37948L,37949L,37950L,
8770537951L,37952L,37953L,37954L,37955L,37956L,37957L,37958L,37959L,37960L,
8770637961L,37962L,37963L,37964L,37965L,37966L,37967L,37968L,37969L,37970L,
8770737971L,37972L,37973L,37974L,37975L,37976L,37977L,37978L,37979L,37980L,
8770837981L,37982L,37983L,37984L,37985L,37986L,37987L,37988L,37989L,37990L,
8770937991L,37992L,37993L,37994L,37995L,37996L,37997L,37998L,37999L,38000L,
8771038001L,38002L,38003L,38004L,38005L,38006L,38007L,38008L,38009L,38010L,
8771138011L,38012L,38013L,38014L,38015L,38016L,38017L,38018L,38019L,38020L,
8771238021L,38022L,38023L,38024L,38025L,38026L,38027L,38028L,38029L,38030L,
8771338031L,38032L,38033L,38034L,38035L,38036L,38037L,38038L,38039L,38040L,
8771438041L,38042L,38043L,38044L,38045L,38046L,38047L,38048L,38049L,38050L,
8771538051L,38052L,38053L,38054L,38055L,38056L,38057L,38058L,38059L,38060L,
8771638061L,38062L,38063L,38064L,38065L,38066L,38067L,38068L,38069L,38070L,
8771738071L,38072L,38073L,38074L,38075L,38076L,38077L,38078L,38079L,38080L,
8771838081L,38082L,38083L,38084L,38085L,38086L,38087L,38088L,38089L,38090L,
8771938091L,38092L,38093L,38094L,38095L,38096L,38097L,38098L,38099L,38100L,
8772038101L,38102L,38103L,38104L,38105L,38106L,38107L,38108L,38109L,38110L,
8772138111L,38112L,38113L,38114L,38115L,38116L,38117L,38118L,38119L,38120L,
8772238121L,38122L,38123L,38124L,38125L,38126L,38127L,38128L,38129L,38130L,
8772338131L,38132L,38133L,38134L,38135L,38136L,38137L,38138L,38139L,38140L,
8772438141L,38142L,38143L,38144L,38145L,38146L,38147L,38148L,38149L,38150L,
8772538151L,38152L,38153L,38154L,38155L,38156L,38157L,38158L,38159L,38160L,
8772638161L,38162L,38163L,38164L,38165L,38166L,38167L,38168L,38169L,38170L,
8772738171L,38172L,38173L,38174L,38175L,38176L,38177L,38178L,38179L,38180L,
8772838181L,38182L,38183L,38184L,38185L,38186L,38187L,38188L,38189L,38190L,
8772938191L,38192L,38193L,38194L,38195L,38196L,38197L,38198L,38199L,38200L,
8773038201L,38202L,38203L,38204L,38205L,38206L,38207L,38208L,38209L,38210L,
8773138211L,38212L,38213L,38214L,38215L,38216L,38217L,38218L,38219L,38220L,
8773238221L,38222L,38223L,38224L,38225L,38226L,38227L,38228L,38229L,38230L,
8773338231L,38232L,38233L,38234L,38235L,38236L,38237L,38238L,38239L,38240L,
8773438241L,38242L,38243L,38244L,38245L,38246L,38247L,38248L,38249L,38250L,
8773538251L,38252L,38253L,38254L,38255L,38256L,38257L,38258L,38259L,38260L,
8773638261L,38262L,38263L,38264L,38265L,38266L,38267L,38268L,38269L,38270L,
8773738271L,38272L,38273L,38274L,38275L,38276L,38277L,38278L,38279L,38280L,
8773838281L,38282L,38283L,38284L,38285L,38286L,38287L,38288L,38289L,38290L,
8773938291L,38292L,38293L,38294L,38295L,38296L,38297L,38298L,38299L,38300L,
8774038301L,38302L,38303L,38304L,38305L,38306L,38307L,38308L,38309L,38310L,
8774138311L,38312L,38313L,38314L,38315L,38316L,38317L,38318L,38319L,38320L,
8774238321L,38322L,38323L,38324L,38325L,38326L,38327L,38328L,38329L,38330L,
8774338331L,38332L,38333L,38334L,38335L,38336L,38337L,38338L,38339L,38340L,
8774438341L,38342L,38343L,38344L,38345L,38346L,38347L,38348L,38349L,38350L,
8774538351L,38352L,38353L,38354L,38355L,38356L,38357L,38358L,38359L,38360L,
8774638361L,38362L,38363L,38364L,38365L,38366L,38367L,38368L,38369L,38370L,
8774738371L,38372L,38373L,38374L,38375L,38376L,38377L,38378L,38379L,38380L,
8774838381L,38382L,38383L,38384L,38385L,38386L,38387L,38388L,38389L,38390L,
8774938391L,38392L,38393L,38394L,38395L,38396L,38397L,38398L,38399L,38400L,
8775038401L,38402L,38403L,38404L,38405L,38406L,38407L,38408L,38409L,38410L,
8775138411L,38412L,38413L,38414L,38415L,38416L,38417L,38418L,38419L,38420L,
8775238421L,38422L,38423L,38424L,38425L,38426L,38427L,38428L,38429L,38430L,
8775338431L,38432L,38433L,38434L,38435L,38436L,38437L,38438L,38439L,38440L,
8775438441L,38442L,38443L,38444L,38445L,38446L,38447L,38448L,38449L,38450L,
8775538451L,38452L,38453L,38454L,38455L,38456L,38457L,38458L,38459L,38460L,
8775638461L,38462L,38463L,38464L,38465L,38466L,38467L,38468L,38469L,38470L,
8775738471L,38472L,38473L,38474L,38475L,38476L,38477L,38478L,38479L,38480L,
8775838481L,38482L,38483L,38484L,38485L,38486L,38487L,38488L,38489L,38490L,
8775938491L,38492L,38493L,38494L,38495L,38496L,38497L,38498L,38499L,38500L,
8776038501L,38502L,38503L,38504L,38505L,38506L,38507L,38508L,38509L,38510L,
8776138511L,38512L,38513L,38514L,38515L,38516L,38517L,38518L,38519L,38520L,
8776238521L,38522L,38523L,38524L,38525L,38526L,38527L,38528L,38529L,38530L,
8776338531L,38532L,38533L,38534L,38535L,38536L,38537L,38538L,38539L,38540L,
8776438541L,38542L,38543L,38544L,38545L,38546L,38547L,38548L,38549L,38550L,
8776538551L,38552L,38553L,38554L,38555L,38556L,38557L,38558L,38559L,38560L,
8776638561L,38562L,38563L,38564L,38565L,38566L,38567L,38568L,38569L,38570L,
8776738571L,38572L,38573L,38574L,38575L,38576L,38577L,38578L,38579L,38580L,
8776838581L,38582L,38583L,38584L,38585L,38586L,38587L,38588L,38589L,38590L,
8776938591L,38592L,38593L,38594L,38595L,38596L,38597L,38598L,38599L,38600L,
8777038601L,38602L,38603L,38604L,38605L,38606L,38607L,38608L,38609L,38610L,
8777138611L,38612L,38613L,38614L,38615L,38616L,38617L,38618L,38619L,38620L,
8777238621L,38622L,38623L,38624L,38625L,38626L,38627L,38628L,38629L,38630L,
8777338631L,38632L,38633L,38634L,38635L,38636L,38637L,38638L,38639L,38640L,
8777438641L,38642L,38643L,38644L,38645L,38646L,38647L,38648L,38649L,38650L,
8777538651L,38652L,38653L,38654L,38655L,38656L,38657L,38658L,38659L,38660L,
8777638661L,38662L,38663L,38664L,38665L,38666L,38667L,38668L,38669L,38670L,
8777738671L,38672L,38673L,38674L,38675L,38676L,38677L,38678L,38679L,38680L,
8777838681L,38682L,38683L,38684L,38685L,38686L,38687L,38688L,38689L,38690L,
8777938691L,38692L,38693L,38694L,38695L,38696L,38697L,38698L,38699L,38700L,
8778038701L,38702L,38703L,38704L,38705L,38706L,38707L,38708L,38709L,38710L,
8778138711L,38712L,38713L,38714L,38715L,38716L,38717L,38718L,38719L,38720L,
8778238721L,38722L,38723L,38724L,38725L,38726L,38727L,38728L,38729L,38730L,
8778338731L,38732L,38733L,38734L,38735L,38736L,38737L,38738L,38739L,38740L,
8778438741L,38742L,38743L,38744L,38745L,38746L,38747L,38748L,38749L,38750L,
8778538751L,38752L,38753L,38754L,38755L,38756L,38757L,38758L,38759L,38760L,
8778638761L,38762L,38763L,38764L,38765L,38766L,38767L,38768L,38769L,38770L,
8778738771L,38772L,38773L,38774L,38775L,38776L,38777L,38778L,38779L,38780L,
8778838781L,38782L,38783L,38784L,38785L,38786L,38787L,38788L,38789L,38790L,
8778938791L,38792L,38793L,38794L,38795L,38796L,38797L,38798L,38799L,38800L,
8779038801L,38802L,38803L,38804L,38805L,38806L,38807L,38808L,38809L,38810L,
8779138811L,38812L,38813L,38814L,38815L,38816L,38817L,38818L,38819L,38820L,
8779238821L,38822L,38823L,38824L,38825L,38826L,38827L,38828L,38829L,38830L,
8779338831L,38832L,38833L,38834L,38835L,38836L,38837L,38838L,38839L,38840L,
8779438841L,38842L,38843L,38844L,38845L,38846L,38847L,38848L,38849L,38850L,
8779538851L,38852L,38853L,38854L,38855L,38856L,38857L,38858L,38859L,38860L,
8779638861L,38862L,38863L,38864L,38865L,38866L,38867L,38868L,38869L,38870L,
8779738871L,38872L,38873L,38874L,38875L,38876L,38877L,38878L,38879L,38880L,
8779838881L,38882L,38883L,38884L,38885L,38886L,38887L,38888L,38889L,38890L,
8779938891L,38892L,38893L,38894L,38895L,38896L,38897L,38898L,38899L,38900L,
8780038901L,38902L,38903L,38904L,38905L,38906L,38907L,38908L,38909L,38910L,
8780138911L,38912L,38913L,38914L,38915L,38916L,38917L,38918L,38919L,38920L,
8780238921L,38922L,38923L,38924L,38925L,38926L,38927L,38928L,38929L,38930L,
8780338931L,38932L,38933L,38934L,38935L,38936L,38937L,38938L,38939L,38940L,
8780438941L,38942L,38943L,38944L,38945L,38946L,38947L,38948L,38949L,38950L,
8780538951L,38952L,38953L,38954L,38955L,38956L,38957L,38958L,38959L,38960L,
8780638961L,38962L,38963L,38964L,38965L,38966L,38967L,38968L,38969L,38970L,
8780738971L,38972L,38973L,38974L,38975L,38976L,38977L,38978L,38979L,38980L,
8780838981L,38982L,38983L,38984L,38985L,38986L,38987L,38988L,38989L,38990L,
8780938991L,38992L,38993L,38994L,38995L,38996L,38997L,38998L,38999L,39000L,
8781039001L,39002L,39003L,39004L,39005L,39006L,39007L,39008L,39009L,39010L,
8781139011L,39012L,39013L,39014L,39015L,39016L,39017L,39018L,39019L,39020L,
8781239021L,39022L,39023L,39024L,39025L,39026L,39027L,39028L,39029L,39030L,
8781339031L,39032L,39033L,39034L,39035L,39036L,39037L,39038L,39039L,39040L,
8781439041L,39042L,39043L,39044L,39045L,39046L,39047L,39048L,39049L,39050L,
8781539051L,39052L,39053L,39054L,39055L,39056L,39057L,39058L,39059L,39060L,
8781639061L,39062L,39063L,39064L,39065L,39066L,39067L,39068L,39069L,39070L,
8781739071L,39072L,39073L,39074L,39075L,39076L,39077L,39078L,39079L,39080L,
8781839081L,39082L,39083L,39084L,39085L,39086L,39087L,39088L,39089L,39090L,
8781939091L,39092L,39093L,39094L,39095L,39096L,39097L,39098L,39099L,39100L,
8782039101L,39102L,39103L,39104L,39105L,39106L,39107L,39108L,39109L,39110L,
8782139111L,39112L,39113L,39114L,39115L,39116L,39117L,39118L,39119L,39120L,
8782239121L,39122L,39123L,39124L,39125L,39126L,39127L,39128L,39129L,39130L,
8782339131L,39132L,39133L,39134L,39135L,39136L,39137L,39138L,39139L,39140L,
8782439141L,39142L,39143L,39144L,39145L,39146L,39147L,39148L,39149L,39150L,
8782539151L,39152L,39153L,39154L,39155L,39156L,39157L,39158L,39159L,39160L,
8782639161L,39162L,39163L,39164L,39165L,39166L,39167L,39168L,39169L,39170L,
8782739171L,39172L,39173L,39174L,39175L,39176L,39177L,39178L,39179L,39180L,
8782839181L,39182L,39183L,39184L,39185L,39186L,39187L,39188L,39189L,39190L,
8782939191L,39192L,39193L,39194L,39195L,39196L,39197L,39198L,39199L,39200L,
8783039201L,39202L,39203L,39204L,39205L,39206L,39207L,39208L,39209L,39210L,
8783139211L,39212L,39213L,39214L,39215L,39216L,39217L,39218L,39219L,39220L,
8783239221L,39222L,39223L,39224L,39225L,39226L,39227L,39228L,39229L,39230L,
8783339231L,39232L,39233L,39234L,39235L,39236L,39237L,39238L,39239L,39240L,
8783439241L,39242L,39243L,39244L,39245L,39246L,39247L,39248L,39249L,39250L,
8783539251L,39252L,39253L,39254L,39255L,39256L,39257L,39258L,39259L,39260L,
8783639261L,39262L,39263L,39264L,39265L,39266L,39267L,39268L,39269L,39270L,
8783739271L,39272L,39273L,39274L,39275L,39276L,39277L,39278L,39279L,39280L,
8783839281L,39282L,39283L,39284L,39285L,39286L,39287L,39288L,39289L,39290L,
8783939291L,39292L,39293L,39294L,39295L,39296L,39297L,39298L,39299L,39300L,
8784039301L,39302L,39303L,39304L,39305L,39306L,39307L,39308L,39309L,39310L,
8784139311L,39312L,39313L,39314L,39315L,39316L,39317L,39318L,39319L,39320L,
8784239321L,39322L,39323L,39324L,39325L,39326L,39327L,39328L,39329L,39330L,
8784339331L,39332L,39333L,39334L,39335L,39336L,39337L,39338L,39339L,39340L,
8784439341L,39342L,39343L,39344L,39345L,39346L,39347L,39348L,39349L,39350L,
8784539351L,39352L,39353L,39354L,39355L,39356L,39357L,39358L,39359L,39360L,
8784639361L,39362L,39363L,39364L,39365L,39366L,39367L,39368L,39369L,39370L,
8784739371L,39372L,39373L,39374L,39375L,39376L,39377L,39378L,39379L,39380L,
8784839381L,39382L,39383L,39384L,39385L,39386L,39387L,39388L,39389L,39390L,
8784939391L,39392L,39393L,39394L,39395L,39396L,39397L,39398L,39399L,39400L,
8785039401L,39402L,39403L,39404L,39405L,39406L,39407L,39408L,39409L,39410L,
8785139411L,39412L,39413L,39414L,39415L,39416L,39417L,39418L,39419L,39420L,
8785239421L,39422L,39423L,39424L,39425L,39426L,39427L,39428L,39429L,39430L,
8785339431L,39432L,39433L,39434L,39435L,39436L,39437L,39438L,39439L,39440L,
8785439441L,39442L,39443L,39444L,39445L,39446L,39447L,39448L,39449L,39450L,
8785539451L,39452L,39453L,39454L,39455L,39456L,39457L,39458L,39459L,39460L,
8785639461L,39462L,39463L,39464L,39465L,39466L,39467L,39468L,39469L,39470L,
8785739471L,39472L,39473L,39474L,39475L,39476L,39477L,39478L,39479L,39480L,
8785839481L,39482L,39483L,39484L,39485L,39486L,39487L,39488L,39489L,39490L,
8785939491L,39492L,39493L,39494L,39495L,39496L,39497L,39498L,39499L,39500L,
8786039501L,39502L,39503L,39504L,39505L,39506L,39507L,39508L,39509L,39510L,
8786139511L,39512L,39513L,39514L,39515L,39516L,39517L,39518L,39519L,39520L,
8786239521L,39522L,39523L,39524L,39525L,39526L,39527L,39528L,39529L,39530L,
8786339531L,39532L,39533L,39534L,39535L,39536L,39537L,39538L,39539L,39540L,
8786439541L,39542L,39543L,39544L,39545L,39546L,39547L,39548L,39549L,39550L,
8786539551L,39552L,39553L,39554L,39555L,39556L,39557L,39558L,39559L,39560L,
8786639561L,39562L,39563L,39564L,39565L,39566L,39567L,39568L,39569L,39570L,
8786739571L,39572L,39573L,39574L,39575L,39576L,39577L,39578L,39579L,39580L,
8786839581L,39582L,39583L,39584L,39585L,39586L,39587L,39588L,39589L,39590L,
8786939591L,39592L,39593L,39594L,39595L,39596L,39597L,39598L,39599L,39600L,
8787039601L,39602L,39603L,39604L,39605L,39606L,39607L,39608L,39609L,39610L,
8787139611L,39612L,39613L,39614L,39615L,39616L,39617L,39618L,39619L,39620L,
8787239621L,39622L,39623L,39624L,39625L,39626L,39627L,39628L,39629L,39630L,
8787339631L,39632L,39633L,39634L,39635L,39636L,39637L,39638L,39639L,39640L,
8787439641L,39642L,39643L,39644L,39645L,39646L,39647L,39648L,39649L,39650L,
8787539651L,39652L,39653L,39654L,39655L,39656L,39657L,39658L,39659L,39660L,
8787639661L,39662L,39663L,39664L,39665L,39666L,39667L,39668L,39669L,39670L,
8787739671L,39672L,39673L,39674L,39675L,39676L,39677L,39678L,39679L,39680L,
8787839681L,39682L,39683L,39684L,39685L,39686L,39687L,39688L,39689L,39690L,
8787939691L,39692L,39693L,39694L,39695L,39696L,39697L,39698L,39699L,39700L,
8788039701L,39702L,39703L,39704L,39705L,39706L,39707L,39708L,39709L,39710L,
8788139711L,39712L,39713L,39714L,39715L,39716L,39717L,39718L,39719L,39720L,
8788239721L,39722L,39723L,39724L,39725L,39726L,39727L,39728L,39729L,39730L,
8788339731L,39732L,39733L,39734L,39735L,39736L,39737L,39738L,39739L,39740L,
8788439741L,39742L,39743L,39744L,39745L,39746L,39747L,39748L,39749L,39750L,
8788539751L,39752L,39753L,39754L,39755L,39756L,39757L,39758L,39759L,39760L,
8788639761L,39762L,39763L,39764L,39765L,39766L,39767L,39768L,39769L,39770L,
8788739771L,39772L,39773L,39774L,39775L,39776L,39777L,39778L,39779L,39780L,
8788839781L,39782L,39783L,39784L,39785L,39786L,39787L,39788L,39789L,39790L,
8788939791L,39792L,39793L,39794L,39795L,39796L,39797L,39798L,39799L,39800L,
8789039801L,39802L,39803L,39804L,39805L,39806L,39807L,39808L,39809L,39810L,
8789139811L,39812L,39813L,39814L,39815L,39816L,39817L,39818L,39819L,39820L,
8789239821L,39822L,39823L,39824L,39825L,39826L,39827L,39828L,39829L,39830L,
8789339831L,39832L,39833L,39834L,39835L,39836L,39837L,39838L,39839L,39840L,
8789439841L,39842L,39843L,39844L,39845L,39846L,39847L,39848L,39849L,39850L,
8789539851L,39852L,39853L,39854L,39855L,39856L,39857L,39858L,39859L,39860L,
8789639861L,39862L,39863L,39864L,39865L,39866L,39867L,39868L,39869L,39870L,
8789739871L,39872L,39873L,39874L,39875L,39876L,39877L,39878L,39879L,39880L,
8789839881L,39882L,39883L,39884L,39885L,39886L,39887L,39888L,39889L,39890L,
8789939891L,39892L,39893L,39894L,39895L,39896L,39897L,39898L,39899L,39900L,
8790039901L,39902L,39903L,39904L,39905L,39906L,39907L,39908L,39909L,39910L,
8790139911L,39912L,39913L,39914L,39915L,39916L,39917L,39918L,39919L,39920L,
8790239921L,39922L,39923L,39924L,39925L,39926L,39927L,39928L,39929L,39930L,
8790339931L,39932L,39933L,39934L,39935L,39936L,39937L,39938L,39939L,39940L,
8790439941L,39942L,39943L,39944L,39945L,39946L,39947L,39948L,39949L,39950L,
8790539951L,39952L,39953L,39954L,39955L,39956L,39957L,39958L,39959L,39960L,
8790639961L,39962L,39963L,39964L,39965L,39966L,39967L,39968L,39969L,39970L,
8790739971L,39972L,39973L,39974L,39975L,39976L,39977L,39978L,39979L,39980L,
8790839981L,39982L,39983L,39984L,39985L,39986L,39987L,39988L,39989L,39990L,
8790939991L,39992L,39993L,39994L,39995L,39996L,39997L,39998L,39999L,40000L,
8791040001L,40002L,40003L,40004L,40005L,40006L,40007L,40008L,40009L,40010L,
8791140011L,40012L,40013L,40014L,40015L,40016L,40017L,40018L,40019L,40020L,
8791240021L,40022L,40023L,40024L,40025L,40026L,40027L,40028L,40029L,40030L,
8791340031L,40032L,40033L,40034L,40035L,40036L,40037L,40038L,40039L,40040L,
8791440041L,40042L,40043L,40044L,40045L,40046L,40047L,40048L,40049L,40050L,
8791540051L,40052L,40053L,40054L,40055L,40056L,40057L,40058L,40059L,40060L,
8791640061L,40062L,40063L,40064L,40065L,40066L,40067L,40068L,40069L,40070L,
8791740071L,40072L,40073L,40074L,40075L,40076L,40077L,40078L,40079L,40080L,
8791840081L,40082L,40083L,40084L,40085L,40086L,40087L,40088L,40089L,40090L,
8791940091L,40092L,40093L,40094L,40095L,40096L,40097L,40098L,40099L,40100L,
8792040101L,40102L,40103L,40104L,40105L,40106L,40107L,40108L,40109L,40110L,
8792140111L,40112L,40113L,40114L,40115L,40116L,40117L,40118L,40119L,40120L,
8792240121L,40122L,40123L,40124L,40125L,40126L,40127L,40128L,40129L,40130L,
8792340131L,40132L,40133L,40134L,40135L,40136L,40137L,40138L,40139L,40140L,
8792440141L,40142L,40143L,40144L,40145L,40146L,40147L,40148L,40149L,40150L,
8792540151L,40152L,40153L,40154L,40155L,40156L,40157L,40158L,40159L,40160L,
8792640161L,40162L,40163L,40164L,40165L,40166L,40167L,40168L,40169L,40170L,
8792740171L,40172L,40173L,40174L,40175L,40176L,40177L,40178L,40179L,40180L,
8792840181L,40182L,40183L,40184L,40185L,40186L,40187L,40188L,40189L,40190L,
8792940191L,40192L,40193L,40194L,40195L,40196L,40197L,40198L,40199L,40200L,
8793040201L,40202L,40203L,40204L,40205L,40206L,40207L,40208L,40209L,40210L,
8793140211L,40212L,40213L,40214L,40215L,40216L,40217L,40218L,40219L,40220L,
8793240221L,40222L,40223L,40224L,40225L,40226L,40227L,40228L,40229L,40230L,
8793340231L,40232L,40233L,40234L,40235L,40236L,40237L,40238L,40239L,40240L,
8793440241L,40242L,40243L,40244L,40245L,40246L,40247L,40248L,40249L,40250L,
8793540251L,40252L,40253L,40254L,40255L,40256L,40257L,40258L,40259L,40260L,
8793640261L,40262L,40263L,40264L,40265L,40266L,40267L,40268L,40269L,40270L,
8793740271L,40272L,40273L,40274L,40275L,40276L,40277L,40278L,40279L,40280L,
8793840281L,40282L,40283L,40284L,40285L,40286L,40287L,40288L,40289L,40290L,
8793940291L,40292L,40293L,40294L,40295L,40296L,40297L,40298L,40299L,40300L,
8794040301L,40302L,40303L,40304L,40305L,40306L,40307L,40308L,40309L,40310L,
8794140311L,40312L,40313L,40314L,40315L,40316L,40317L,40318L,40319L,40320L,
8794240321L,40322L,40323L,40324L,40325L,40326L,40327L,40328L,40329L,40330L,
8794340331L,40332L,40333L,40334L,40335L,40336L,40337L,40338L,40339L,40340L,
8794440341L,40342L,40343L,40344L,40345L,40346L,40347L,40348L,40349L,40350L,
8794540351L,40352L,40353L,40354L,40355L,40356L,40357L,40358L,40359L,40360L,
8794640361L,40362L,40363L,40364L,40365L,40366L,40367L,40368L,40369L,40370L,
8794740371L,40372L,40373L,40374L,40375L,40376L,40377L,40378L,40379L,40380L,
8794840381L,40382L,40383L,40384L,40385L,40386L,40387L,40388L,40389L,40390L,
8794940391L,40392L,40393L,40394L,40395L,40396L,40397L,40398L,40399L,40400L,
8795040401L,40402L,40403L,40404L,40405L,40406L,40407L,40408L,40409L,40410L,
8795140411L,40412L,40413L,40414L,40415L,40416L,40417L,40418L,40419L,40420L,
8795240421L,40422L,40423L,40424L,40425L,40426L,40427L,40428L,40429L,40430L,
8795340431L,40432L,40433L,40434L,40435L,40436L,40437L,40438L,40439L,40440L,
8795440441L,40442L,40443L,40444L,40445L,40446L,40447L,40448L,40449L,40450L,
8795540451L,40452L,40453L,40454L,40455L,40456L,40457L,40458L,40459L,40460L,
8795640461L,40462L,40463L,40464L,40465L,40466L,40467L,40468L,40469L,40470L,
8795740471L,40472L,40473L,40474L,40475L,40476L,40477L,40478L,40479L,40480L,
8795840481L,40482L,40483L,40484L,40485L,40486L,40487L,40488L,40489L,40490L,
8795940491L,40492L,40493L,40494L,40495L,40496L,40497L,40498L,40499L,40500L,
8796040501L,40502L,40503L,40504L,40505L,40506L,40507L,40508L,40509L,40510L,
8796140511L,40512L,40513L,40514L,40515L,40516L,40517L,40518L,40519L,40520L,
8796240521L,40522L,40523L,40524L,40525L,40526L,40527L,40528L,40529L,40530L,
8796340531L,40532L,40533L,40534L,40535L,40536L,40537L,40538L,40539L,40540L,
8796440541L,40542L,40543L,40544L,40545L,40546L,40547L,40548L,40549L,40550L,
8796540551L,40552L,40553L,40554L,40555L,40556L,40557L,40558L,40559L,40560L,
8796640561L,40562L,40563L,40564L,40565L,40566L,40567L,40568L,40569L,40570L,
8796740571L,40572L,40573L,40574L,40575L,40576L,40577L,40578L,40579L,40580L,
8796840581L,40582L,40583L,40584L,40585L,40586L,40587L,40588L,40589L,40590L,
8796940591L,40592L,40593L,40594L,40595L,40596L,40597L,40598L,40599L,40600L,
8797040601L,40602L,40603L,40604L,40605L,40606L,40607L,40608L,40609L,40610L,
8797140611L,40612L,40613L,40614L,40615L,40616L,40617L,40618L,40619L,40620L,
8797240621L,40622L,40623L,40624L,40625L,40626L,40627L,40628L,40629L,40630L,
8797340631L,40632L,40633L,40634L,40635L,40636L,40637L,40638L,40639L,40640L,
8797440641L,40642L,40643L,40644L,40645L,40646L,40647L,40648L,40649L,40650L,
8797540651L,40652L,40653L,40654L,40655L,40656L,40657L,40658L,40659L,40660L,
8797640661L,40662L,40663L,40664L,40665L,40666L,40667L,40668L,40669L,40670L,
8797740671L,40672L,40673L,40674L,40675L,40676L,40677L,40678L,40679L,40680L,
8797840681L,40682L,40683L,40684L,40685L,40686L,40687L,40688L,40689L,40690L,
8797940691L,40692L,40693L,40694L,40695L,40696L,40697L,40698L,40699L,40700L,
8798040701L,40702L,40703L,40704L,40705L,40706L,40707L,40708L,40709L,40710L,
8798140711L,40712L,40713L,40714L,40715L,40716L,40717L,40718L,40719L,40720L,
8798240721L,40722L,40723L,40724L,40725L,40726L,40727L,40728L,40729L,40730L,
8798340731L,40732L,40733L,40734L,40735L,40736L,40737L,40738L,40739L,40740L,
8798440741L,40742L,40743L,40744L,40745L,40746L,40747L,40748L,40749L,40750L,
8798540751L,40752L,40753L,40754L,40755L,40756L,40757L,40758L,40759L,40760L,
8798640761L,40762L,40763L,40764L,40765L,40766L,40767L,40768L,40769L,40770L,
8798740771L,40772L,40773L,40774L,40775L,40776L,40777L,40778L,40779L,40780L,
8798840781L,40782L,40783L,40784L,40785L,40786L,40787L,40788L,40789L,40790L,
8798940791L,40792L,40793L,40794L,40795L,40796L,40797L,40798L,40799L,40800L,
8799040801L,40802L,40803L,40804L,40805L,40806L,40807L,40808L,40809L,40810L,
8799140811L,40812L,40813L,40814L,40815L,40816L,40817L,40818L,40819L,40820L,
8799240821L,40822L,40823L,40824L,40825L,40826L,40827L,40828L,40829L,40830L,
8799340831L,40832L,40833L,40834L,40835L,40836L,40837L,40838L,40839L,40840L,
8799440841L,40842L,40843L,40844L,40845L,40846L,40847L,40848L,40849L,40850L,
8799540851L,40852L,40853L,40854L,40855L,40856L,40857L,40858L,40859L,40860L,
8799640861L,40862L,40863L,40864L,40865L,40866L,40867L,40868L,40869L,40870L,
8799740871L,40872L,40873L,40874L,40875L,40876L,40877L,40878L,40879L,40880L,
8799840881L,40882L,40883L,40884L,40885L,40886L,40887L,40888L,40889L,40890L,
8799940891L,40892L,40893L,40894L,40895L,40896L,40897L,40898L,40899L,40900L,
8800040901L,40902L,40903L,40904L,40905L,40906L,40907L,40908L,40909L,40910L,
8800140911L,40912L,40913L,40914L,40915L,40916L,40917L,40918L,40919L,40920L,
8800240921L,40922L,40923L,40924L,40925L,40926L,40927L,40928L,40929L,40930L,
8800340931L,40932L,40933L,40934L,40935L,40936L,40937L,40938L,40939L,40940L,
8800440941L,40942L,40943L,40944L,40945L,40946L,40947L,40948L,40949L,40950L,
8800540951L,40952L,40953L,40954L,40955L,40956L,40957L,40958L,40959L,40960L,
8800640961L,40962L,40963L,40964L,40965L,40966L,40967L,40968L,40969L,40970L,
8800740971L,40972L,40973L,40974L,40975L,40976L,40977L,40978L,40979L,40980L,
8800840981L,40982L,40983L,40984L,40985L,40986L,40987L,40988L,40989L,40990L,
8800940991L,40992L,40993L,40994L,40995L,40996L,40997L,40998L,40999L,41000L,
8801041001L,41002L,41003L,41004L,41005L,41006L,41007L,41008L,41009L,41010L,
8801141011L,41012L,41013L,41014L,41015L,41016L,41017L,41018L,41019L,41020L,
8801241021L,41022L,41023L,41024L,41025L,41026L,41027L,41028L,41029L,41030L,
8801341031L,41032L,41033L,41034L,41035L,41036L,41037L,41038L,41039L,41040L,
8801441041L,41042L,41043L,41044L,41045L,41046L,41047L,41048L,41049L,41050L,
8801541051L,41052L,41053L,41054L,41055L,41056L,41057L,41058L,41059L,41060L,
8801641061L,41062L,41063L,41064L,41065L,41066L,41067L,41068L,41069L,41070L,
8801741071L,41072L,41073L,41074L,41075L,41076L,41077L,41078L,41079L,41080L,
8801841081L,41082L,41083L,41084L,41085L,41086L,41087L,41088L,41089L,41090L,
8801941091L,41092L,41093L,41094L,41095L,41096L,41097L,41098L,41099L,41100L,
8802041101L,41102L,41103L,41104L,41105L,41106L,41107L,41108L,41109L,41110L,
8802141111L,41112L,41113L,41114L,41115L,41116L,41117L,41118L,41119L,41120L,
8802241121L,41122L,41123L,41124L,41125L,41126L,41127L,41128L,41129L,41130L,
8802341131L,41132L,41133L,41134L,41135L,41136L,41137L,41138L,41139L,41140L,
8802441141L,41142L,41143L,41144L,41145L,41146L,41147L,41148L,41149L,41150L,
8802541151L,41152L,41153L,41154L,41155L,41156L,41157L,41158L,41159L,41160L,
8802641161L,41162L,41163L,41164L,41165L,41166L,41167L,41168L,41169L,41170L,
8802741171L,41172L,41173L,41174L,41175L,41176L,41177L,41178L,41179L,41180L,
8802841181L,41182L,41183L,41184L,41185L,41186L,41187L,41188L,41189L,41190L,
8802941191L,41192L,41193L,41194L,41195L,41196L,41197L,41198L,41199L,41200L,
8803041201L,41202L,41203L,41204L,41205L,41206L,41207L,41208L,41209L,41210L,
8803141211L,41212L,41213L,41214L,41215L,41216L,41217L,41218L,41219L,41220L,
8803241221L,41222L,41223L,41224L,41225L,41226L,41227L,41228L,41229L,41230L,
8803341231L,41232L,41233L,41234L,41235L,41236L,41237L,41238L,41239L,41240L,
8803441241L,41242L,41243L,41244L,41245L,41246L,41247L,41248L,41249L,41250L,
8803541251L,41252L,41253L,41254L,41255L,41256L,41257L,41258L,41259L,41260L,
8803641261L,41262L,41263L,41264L,41265L,41266L,41267L,41268L,41269L,41270L,
8803741271L,41272L,41273L,41274L,41275L,41276L,41277L,41278L,41279L,41280L,
8803841281L,41282L,41283L,41284L,41285L,41286L,41287L,41288L,41289L,41290L,
8803941291L,41292L,41293L,41294L,41295L,41296L,41297L,41298L,41299L,41300L,
8804041301L,41302L,41303L,41304L,41305L,41306L,41307L,41308L,41309L,41310L,
8804141311L,41312L,41313L,41314L,41315L,41316L,41317L,41318L,41319L,41320L,
8804241321L,41322L,41323L,41324L,41325L,41326L,41327L,41328L,41329L,41330L,
8804341331L,41332L,41333L,41334L,41335L,41336L,41337L,41338L,41339L,41340L,
8804441341L,41342L,41343L,41344L,41345L,41346L,41347L,41348L,41349L,41350L,
8804541351L,41352L,41353L,41354L,41355L,41356L,41357L,41358L,41359L,41360L,
8804641361L,41362L,41363L,41364L,41365L,41366L,41367L,41368L,41369L,41370L,
8804741371L,41372L,41373L,41374L,41375L,41376L,41377L,41378L,41379L,41380L,
8804841381L,41382L,41383L,41384L,41385L,41386L,41387L,41388L,41389L,41390L,
8804941391L,41392L,41393L,41394L,41395L,41396L,41397L,41398L,41399L,41400L,
8805041401L,41402L,41403L,41404L,41405L,41406L,41407L,41408L,41409L,41410L,
8805141411L,41412L,41413L,41414L,41415L,41416L,41417L,41418L,41419L,41420L,
8805241421L,41422L,41423L,41424L,41425L,41426L,41427L,41428L,41429L,41430L,
8805341431L,41432L,41433L,41434L,41435L,41436L,41437L,41438L,41439L,41440L,
8805441441L,41442L,41443L,41444L,41445L,41446L,41447L,41448L,41449L,41450L,
8805541451L,41452L,41453L,41454L,41455L,41456L,41457L,41458L,41459L,41460L,
8805641461L,41462L,41463L,41464L,41465L,41466L,41467L,41468L,41469L,41470L,
8805741471L,41472L,41473L,41474L,41475L,41476L,41477L,41478L,41479L,41480L,
8805841481L,41482L,41483L,41484L,41485L,41486L,41487L,41488L,41489L,41490L,
8805941491L,41492L,41493L,41494L,41495L,41496L,41497L,41498L,41499L,41500L,
8806041501L,41502L,41503L,41504L,41505L,41506L,41507L,41508L,41509L,41510L,
8806141511L,41512L,41513L,41514L,41515L,41516L,41517L,41518L,41519L,41520L,
8806241521L,41522L,41523L,41524L,41525L,41526L,41527L,41528L,41529L,41530L,
8806341531L,41532L,41533L,41534L,41535L,41536L,41537L,41538L,41539L,41540L,
8806441541L,41542L,41543L,41544L,41545L,41546L,41547L,41548L,41549L,41550L,
8806541551L,41552L,41553L,41554L,41555L,41556L,41557L,41558L,41559L,41560L,
8806641561L,41562L,41563L,41564L,41565L,41566L,41567L,41568L,41569L,41570L,
8806741571L,41572L,41573L,41574L,41575L,41576L,41577L,41578L,41579L,41580L,
8806841581L,41582L,41583L,41584L,41585L,41586L,41587L,41588L,41589L,41590L,
8806941591L,41592L,41593L,41594L,41595L,41596L,41597L,41598L,41599L,41600L,
8807041601L,41602L,41603L,41604L,41605L,41606L,41607L,41608L,41609L,41610L,
8807141611L,41612L,41613L,41614L,41615L,41616L,41617L,41618L,41619L,41620L,
8807241621L,41622L,41623L,41624L,41625L,41626L,41627L,41628L,41629L,41630L,
8807341631L,41632L,41633L,41634L,41635L,41636L,41637L,41638L,41639L,41640L,
8807441641L,41642L,41643L,41644L,41645L,41646L,41647L,41648L,41649L,41650L,
8807541651L,41652L,41653L,41654L,41655L,41656L,41657L,41658L,41659L,41660L,
8807641661L,41662L,41663L,41664L,41665L,41666L,41667L,41668L,41669L,41670L,
8807741671L,41672L,41673L,41674L,41675L,41676L,41677L,41678L,41679L,41680L,
8807841681L,41682L,41683L,41684L,41685L,41686L,41687L,41688L,41689L,41690L,
8807941691L,41692L,41693L,41694L,41695L,41696L,41697L,41698L,41699L,41700L,
8808041701L,41702L,41703L,41704L,41705L,41706L,41707L,41708L,41709L,41710L,
8808141711L,41712L,41713L,41714L,41715L,41716L,41717L,41718L,41719L,41720L,
8808241721L,41722L,41723L,41724L,41725L,41726L,41727L,41728L,41729L,41730L,
8808341731L,41732L,41733L,41734L,41735L,41736L,41737L,41738L,41739L,41740L,
8808441741L,41742L,41743L,41744L,41745L,41746L,41747L,41748L,41749L,41750L,
8808541751L,41752L,41753L,41754L,41755L,41756L,41757L,41758L,41759L,41760L,
8808641761L,41762L,41763L,41764L,41765L,41766L,41767L,41768L,41769L,41770L,
8808741771L,41772L,41773L,41774L,41775L,41776L,41777L,41778L,41779L,41780L,
8808841781L,41782L,41783L,41784L,41785L,41786L,41787L,41788L,41789L,41790L,
8808941791L,41792L,41793L,41794L,41795L,41796L,41797L,41798L,41799L,41800L,
8809041801L,41802L,41803L,41804L,41805L,41806L,41807L,41808L,41809L,41810L,
8809141811L,41812L,41813L,41814L,41815L,41816L,41817L,41818L,41819L,41820L,
8809241821L,41822L,41823L,41824L,41825L,41826L,41827L,41828L,41829L,41830L,
8809341831L,41832L,41833L,41834L,41835L,41836L,41837L,41838L,41839L,41840L,
8809441841L,41842L,41843L,41844L,41845L,41846L,41847L,41848L,41849L,41850L,
8809541851L,41852L,41853L,41854L,41855L,41856L,41857L,41858L,41859L,41860L,
8809641861L,41862L,41863L,41864L,41865L,41866L,41867L,41868L,41869L,41870L,
8809741871L,41872L,41873L,41874L,41875L,41876L,41877L,41878L,41879L,41880L,
8809841881L,41882L,41883L,41884L,41885L,41886L,41887L,41888L,41889L,41890L,
8809941891L,41892L,41893L,41894L,41895L,41896L,41897L,41898L,41899L,41900L,
8810041901L,41902L,41903L,41904L,41905L,41906L,41907L,41908L,41909L,41910L,
8810141911L,41912L,41913L,41914L,41915L,41916L,41917L,41918L,41919L,41920L,
8810241921L,41922L,41923L,41924L,41925L,41926L,41927L,41928L,41929L,41930L,
8810341931L,41932L,41933L,41934L,41935L,41936L,41937L,41938L,41939L,41940L,
8810441941L,41942L,41943L,41944L,41945L,41946L,41947L,41948L,41949L,41950L,
8810541951L,41952L,41953L,41954L,41955L,41956L,41957L,41958L,41959L,41960L,
8810641961L,41962L,41963L,41964L,41965L,41966L,41967L,41968L,41969L,41970L,
8810741971L,41972L,41973L,41974L,41975L,41976L,41977L,41978L,41979L,41980L,
8810841981L,41982L,41983L,41984L,41985L,41986L,41987L,41988L,41989L,41990L,
8810941991L,41992L,41993L,41994L,41995L,41996L,41997L,41998L,41999L,42000L,
8811042001L,42002L,42003L,42004L,42005L,42006L,42007L,42008L,42009L,42010L,
8811142011L,42012L,42013L,42014L,42015L,42016L,42017L,42018L,42019L,42020L,
8811242021L,42022L,42023L,42024L,42025L,42026L,42027L,42028L,42029L,42030L,
8811342031L,42032L,42033L,42034L,42035L,42036L,42037L,42038L,42039L,42040L,
8811442041L,42042L,42043L,42044L,42045L,42046L,42047L,42048L,42049L,42050L,
8811542051L,42052L,42053L,42054L,42055L,42056L,42057L,42058L,42059L,42060L,
8811642061L,42062L,42063L,42064L,42065L,42066L,42067L,42068L,42069L,42070L,
8811742071L,42072L,42073L,42074L,42075L,42076L,42077L,42078L,42079L,42080L,
8811842081L,42082L,42083L,42084L,42085L,42086L,42087L,42088L,42089L,42090L,
8811942091L,42092L,42093L,42094L,42095L,42096L,42097L,42098L,42099L,42100L,
8812042101L,42102L,42103L,42104L,42105L,42106L,42107L,42108L,42109L,42110L,
8812142111L,42112L,42113L,42114L,42115L,42116L,42117L,42118L,42119L,42120L,
8812242121L,42122L,42123L,42124L,42125L,42126L,42127L,42128L,42129L,42130L,
8812342131L,42132L,42133L,42134L,42135L,42136L,42137L,42138L,42139L,42140L,
8812442141L,42142L,42143L,42144L,42145L,42146L,42147L,42148L,42149L,42150L,
8812542151L,42152L,42153L,42154L,42155L,42156L,42157L,42158L,42159L,42160L,
8812642161L,42162L,42163L,42164L,42165L,42166L,42167L,42168L,42169L,42170L,
8812742171L,42172L,42173L,42174L,42175L,42176L,42177L,42178L,42179L,42180L,
8812842181L,42182L,42183L,42184L,42185L,42186L,42187L,42188L,42189L,42190L,
8812942191L,42192L,42193L,42194L,42195L,42196L,42197L,42198L,42199L,42200L,
8813042201L,42202L,42203L,42204L,42205L,42206L,42207L,42208L,42209L,42210L,
8813142211L,42212L,42213L,42214L,42215L,42216L,42217L,42218L,42219L,42220L,
8813242221L,42222L,42223L,42224L,42225L,42226L,42227L,42228L,42229L,42230L,
8813342231L,42232L,42233L,42234L,42235L,42236L,42237L,42238L,42239L,42240L,
8813442241L,42242L,42243L,42244L,42245L,42246L,42247L,42248L,42249L,42250L,
8813542251L,42252L,42253L,42254L,42255L,42256L,42257L,42258L,42259L,42260L,
8813642261L,42262L,42263L,42264L,42265L,42266L,42267L,42268L,42269L,42270L,
8813742271L,42272L,42273L,42274L,42275L,42276L,42277L,42278L,42279L,42280L,
8813842281L,42282L,42283L,42284L,42285L,42286L,42287L,42288L,42289L,42290L,
8813942291L,42292L,42293L,42294L,42295L,42296L,42297L,42298L,42299L,42300L,
8814042301L,42302L,42303L,42304L,42305L,42306L,42307L,42308L,42309L,42310L,
8814142311L,42312L,42313L,42314L,42315L,42316L,42317L,42318L,42319L,42320L,
8814242321L,42322L,42323L,42324L,42325L,42326L,42327L,42328L,42329L,42330L,
8814342331L,42332L,42333L,42334L,42335L,42336L,42337L,42338L,42339L,42340L,
8814442341L,42342L,42343L,42344L,42345L,42346L,42347L,42348L,42349L,42350L,
8814542351L,42352L,42353L,42354L,42355L,42356L,42357L,42358L,42359L,42360L,
8814642361L,42362L,42363L,42364L,42365L,42366L,42367L,42368L,42369L,42370L,
8814742371L,42372L,42373L,42374L,42375L,42376L,42377L,42378L,42379L,42380L,
8814842381L,42382L,42383L,42384L,42385L,42386L,42387L,42388L,42389L,42390L,
8814942391L,42392L,42393L,42394L,42395L,42396L,42397L,42398L,42399L,42400L,
8815042401L,42402L,42403L,42404L,42405L,42406L,42407L,42408L,42409L,42410L,
8815142411L,42412L,42413L,42414L,42415L,42416L,42417L,42418L,42419L,42420L,
8815242421L,42422L,42423L,42424L,42425L,42426L,42427L,42428L,42429L,42430L,
8815342431L,42432L,42433L,42434L,42435L,42436L,42437L,42438L,42439L,42440L,
8815442441L,42442L,42443L,42444L,42445L,42446L,42447L,42448L,42449L,42450L,
8815542451L,42452L,42453L,42454L,42455L,42456L,42457L,42458L,42459L,42460L,
8815642461L,42462L,42463L,42464L,42465L,42466L,42467L,42468L,42469L,42470L,
8815742471L,42472L,42473L,42474L,42475L,42476L,42477L,42478L,42479L,42480L,
8815842481L,42482L,42483L,42484L,42485L,42486L,42487L,42488L,42489L,42490L,
8815942491L,42492L,42493L,42494L,42495L,42496L,42497L,42498L,42499L,42500L,
8816042501L,42502L,42503L,42504L,42505L,42506L,42507L,42508L,42509L,42510L,
8816142511L,42512L,42513L,42514L,42515L,42516L,42517L,42518L,42519L,42520L,
8816242521L,42522L,42523L,42524L,42525L,42526L,42527L,42528L,42529L,42530L,
8816342531L,42532L,42533L,42534L,42535L,42536L,42537L,42538L,42539L,42540L,
8816442541L,42542L,42543L,42544L,42545L,42546L,42547L,42548L,42549L,42550L,
8816542551L,42552L,42553L,42554L,42555L,42556L,42557L,42558L,42559L,42560L,
8816642560L,42562L,42562L,42564L,42564L,42566L,42566L,42568L,42568L,42570L,
8816742570L,42572L,42572L,42574L,42574L,42576L,42576L,42578L,42578L,42580L,
8816842580L,42582L,42582L,42584L,42584L,42586L,42586L,42588L,42588L,42590L,
8816942590L,42592L,42592L,42594L,42594L,42596L,42596L,42598L,42598L,42600L,
8817042600L,42602L,42602L,42604L,42604L,42606L,42607L,42608L,42609L,42610L,
8817142611L,42612L,42613L,42614L,42615L,42616L,42617L,42618L,42619L,42620L,
8817242621L,42622L,42623L,42624L,42624L,42626L,42626L,42628L,42628L,42630L,
8817342630L,42632L,42632L,42634L,42634L,42636L,42636L,42638L,42638L,42640L,
8817442640L,42642L,42642L,42644L,42644L,42646L,42646L,42648L,42648L,42650L,
8817542650L,42652L,42653L,42654L,42655L,42656L,42657L,42658L,42659L,42660L,
8817642661L,42662L,42663L,42664L,42665L,42666L,42667L,42668L,42669L,42670L,
8817742671L,42672L,42673L,42674L,42675L,42676L,42677L,42678L,42679L,42680L,
8817842681L,42682L,42683L,42684L,42685L,42686L,42687L,42688L,42689L,42690L,
8817942691L,42692L,42693L,42694L,42695L,42696L,42697L,42698L,42699L,42700L,
8818042701L,42702L,42703L,42704L,42705L,42706L,42707L,42708L,42709L,42710L,
8818142711L,42712L,42713L,42714L,42715L,42716L,42717L,42718L,42719L,42720L,
8818242721L,42722L,42723L,42724L,42725L,42726L,42727L,42728L,42729L,42730L,
8818342731L,42732L,42733L,42734L,42735L,42736L,42737L,42738L,42739L,42740L,
8818442741L,42742L,42743L,42744L,42745L,42746L,42747L,42748L,42749L,42750L,
8818542751L,42752L,42753L,42754L,42755L,42756L,42757L,42758L,42759L,42760L,
8818642761L,42762L,42763L,42764L,42765L,42766L,42767L,42768L,42769L,42770L,
8818742771L,42772L,42773L,42774L,42775L,42776L,42777L,42778L,42779L,42780L,
8818842781L,42782L,42783L,42784L,42785L,42786L,42786L,42788L,42788L,42790L,
8818942790L,42792L,42792L,42794L,42794L,42796L,42796L,42798L,42798L,42800L,
8819042801L,42802L,42802L,42804L,42804L,42806L,42806L,42808L,42808L,42810L,
8819142810L,42812L,42812L,42814L,42814L,42816L,42816L,42818L,42818L,42820L,
8819242820L,42822L,42822L,42824L,42824L,42826L,42826L,42828L,42828L,42830L,
8819342830L,42832L,42832L,42834L,42834L,42836L,42836L,42838L,42838L,42840L,
8819442840L,42842L,42842L,42844L,42844L,42846L,42846L,42848L,42848L,42850L,
8819542850L,42852L,42852L,42854L,42854L,42856L,42856L,42858L,42858L,42860L,
8819642860L,42862L,42862L,42864L,42865L,42866L,42867L,42868L,42869L,42870L,
8819742871L,42872L,42873L,42873L,42875L,42875L,42877L,42878L,42878L,42880L,
8819842880L,42882L,42882L,42884L,42884L,42886L,42886L,42888L,42889L,42890L,
8819942891L,42891L,42893L,42894L,42895L,42896L,42896L,42898L,42898L,42900L,
8820042901L,42902L,42902L,42904L,42904L,42906L,42906L,42908L,42908L,42910L,
8820142910L,42912L,42912L,42914L,42914L,42916L,42916L,42918L,42918L,42920L,
8820242920L,42922L,42923L,42924L,42925L,42926L,42927L,42928L,42929L,42930L,
8820342931L,42932L,42932L,42934L,42934L,42936L,42937L,42938L,42939L,42940L,
8820442941L,42942L,42943L,42944L,42945L,42946L,42947L,42948L,42949L,42950L,
8820542951L,42952L,42953L,42954L,42955L,42956L,42957L,42958L,42959L,42960L,
8820642961L,42962L,42963L,42964L,42965L,42966L,42967L,42968L,42969L,42970L,
8820742971L,42972L,42973L,42974L,42975L,42976L,42977L,42978L,42979L,42980L,
8820842981L,42982L,42983L,42984L,42985L,42986L,42987L,42988L,42989L,42990L,
8820942991L,42992L,42993L,42994L,42995L,42996L,42997L,42998L,42999L,43000L,
8821043001L,43002L,43003L,43004L,43005L,43006L,43007L,43008L,43009L,43010L,
8821143011L,43012L,43013L,43014L,43015L,43016L,43017L,43018L,43019L,43020L,
8821243021L,43022L,43023L,43024L,43025L,43026L,43027L,43028L,43029L,43030L,
8821343031L,43032L,43033L,43034L,43035L,43036L,43037L,43038L,43039L,43040L,
8821443041L,43042L,43043L,43044L,43045L,43046L,43047L,43048L,43049L,43050L,
8821543051L,43052L,43053L,43054L,43055L,43056L,43057L,43058L,43059L,43060L,
8821643061L,43062L,43063L,43064L,43065L,43066L,43067L,43068L,43069L,43070L,
8821743071L,43072L,43073L,43074L,43075L,43076L,43077L,43078L,43079L,43080L,
8821843081L,43082L,43083L,43084L,43085L,43086L,43087L,43088L,43089L,43090L,
8821943091L,43092L,43093L,43094L,43095L,43096L,43097L,43098L,43099L,43100L,
8822043101L,43102L,43103L,43104L,43105L,43106L,43107L,43108L,43109L,43110L,
8822143111L,43112L,43113L,43114L,43115L,43116L,43117L,43118L,43119L,43120L,
8822243121L,43122L,43123L,43124L,43125L,43126L,43127L,43128L,43129L,43130L,
8822343131L,43132L,43133L,43134L,43135L,43136L,43137L,43138L,43139L,43140L,
8822443141L,43142L,43143L,43144L,43145L,43146L,43147L,43148L,43149L,43150L,
8822543151L,43152L,43153L,43154L,43155L,43156L,43157L,43158L,43159L,43160L,
8822643161L,43162L,43163L,43164L,43165L,43166L,43167L,43168L,43169L,43170L,
8822743171L,43172L,43173L,43174L,43175L,43176L,43177L,43178L,43179L,43180L,
8822843181L,43182L,43183L,43184L,43185L,43186L,43187L,43188L,43189L,43190L,
8822943191L,43192L,43193L,43194L,43195L,43196L,43197L,43198L,43199L,43200L,
8823043201L,43202L,43203L,43204L,43205L,43206L,43207L,43208L,43209L,43210L,
8823143211L,43212L,43213L,43214L,43215L,43216L,43217L,43218L,43219L,43220L,
8823243221L,43222L,43223L,43224L,43225L,43226L,43227L,43228L,43229L,43230L,
8823343231L,43232L,43233L,43234L,43235L,43236L,43237L,43238L,43239L,43240L,
8823443241L,43242L,43243L,43244L,43245L,43246L,43247L,43248L,43249L,43250L,
8823543251L,43252L,43253L,43254L,43255L,43256L,43257L,43258L,43259L,43260L,
8823643261L,43262L,43263L,43264L,43265L,43266L,43267L,43268L,43269L,43270L,
8823743271L,43272L,43273L,43274L,43275L,43276L,43277L,43278L,43279L,43280L,
8823843281L,43282L,43283L,43284L,43285L,43286L,43287L,43288L,43289L,43290L,
8823943291L,43292L,43293L,43294L,43295L,43296L,43297L,43298L,43299L,43300L,
8824043301L,43302L,43303L,43304L,43305L,43306L,43307L,43308L,43309L,43310L,
8824143311L,43312L,43313L,43314L,43315L,43316L,43317L,43318L,43319L,43320L,
8824243321L,43322L,43323L,43324L,43325L,43326L,43327L,43328L,43329L,43330L,
8824343331L,43332L,43333L,43334L,43335L,43336L,43337L,43338L,43339L,43340L,
8824443341L,43342L,43343L,43344L,43345L,43346L,43347L,43348L,43349L,43350L,
8824543351L,43352L,43353L,43354L,43355L,43356L,43357L,43358L,43359L,43360L,
8824643361L,43362L,43363L,43364L,43365L,43366L,43367L,43368L,43369L,43370L,
8824743371L,43372L,43373L,43374L,43375L,43376L,43377L,43378L,43379L,43380L,
8824843381L,43382L,43383L,43384L,43385L,43386L,43387L,43388L,43389L,43390L,
8824943391L,43392L,43393L,43394L,43395L,43396L,43397L,43398L,43399L,43400L,
8825043401L,43402L,43403L,43404L,43405L,43406L,43407L,43408L,43409L,43410L,
8825143411L,43412L,43413L,43414L,43415L,43416L,43417L,43418L,43419L,43420L,
8825243421L,43422L,43423L,43424L,43425L,43426L,43427L,43428L,43429L,43430L,
8825343431L,43432L,43433L,43434L,43435L,43436L,43437L,43438L,43439L,43440L,
8825443441L,43442L,43443L,43444L,43445L,43446L,43447L,43448L,43449L,43450L,
8825543451L,43452L,43453L,43454L,43455L,43456L,43457L,43458L,43459L,43460L,
8825643461L,43462L,43463L,43464L,43465L,43466L,43467L,43468L,43469L,43470L,
8825743471L,43472L,43473L,43474L,43475L,43476L,43477L,43478L,43479L,43480L,
8825843481L,43482L,43483L,43484L,43485L,43486L,43487L,43488L,43489L,43490L,
8825943491L,43492L,43493L,43494L,43495L,43496L,43497L,43498L,43499L,43500L,
8826043501L,43502L,43503L,43504L,43505L,43506L,43507L,43508L,43509L,43510L,
8826143511L,43512L,43513L,43514L,43515L,43516L,43517L,43518L,43519L,43520L,
8826243521L,43522L,43523L,43524L,43525L,43526L,43527L,43528L,43529L,43530L,
8826343531L,43532L,43533L,43534L,43535L,43536L,43537L,43538L,43539L,43540L,
8826443541L,43542L,43543L,43544L,43545L,43546L,43547L,43548L,43549L,43550L,
8826543551L,43552L,43553L,43554L,43555L,43556L,43557L,43558L,43559L,43560L,
8826643561L,43562L,43563L,43564L,43565L,43566L,43567L,43568L,43569L,43570L,
8826743571L,43572L,43573L,43574L,43575L,43576L,43577L,43578L,43579L,43580L,
8826843581L,43582L,43583L,43584L,43585L,43586L,43587L,43588L,43589L,43590L,
8826943591L,43592L,43593L,43594L,43595L,43596L,43597L,43598L,43599L,43600L,
8827043601L,43602L,43603L,43604L,43605L,43606L,43607L,43608L,43609L,43610L,
8827143611L,43612L,43613L,43614L,43615L,43616L,43617L,43618L,43619L,43620L,
8827243621L,43622L,43623L,43624L,43625L,43626L,43627L,43628L,43629L,43630L,
8827343631L,43632L,43633L,43634L,43635L,43636L,43637L,43638L,43639L,43640L,
8827443641L,43642L,43643L,43644L,43645L,43646L,43647L,43648L,43649L,43650L,
8827543651L,43652L,43653L,43654L,43655L,43656L,43657L,43658L,43659L,43660L,
8827643661L,43662L,43663L,43664L,43665L,43666L,43667L,43668L,43669L,43670L,
8827743671L,43672L,43673L,43674L,43675L,43676L,43677L,43678L,43679L,43680L,
8827843681L,43682L,43683L,43684L,43685L,43686L,43687L,43688L,43689L,43690L,
8827943691L,43692L,43693L,43694L,43695L,43696L,43697L,43698L,43699L,43700L,
8828043701L,43702L,43703L,43704L,43705L,43706L,43707L,43708L,43709L,43710L,
8828143711L,43712L,43713L,43714L,43715L,43716L,43717L,43718L,43719L,43720L,
8828243721L,43722L,43723L,43724L,43725L,43726L,43727L,43728L,43729L,43730L,
8828343731L,43732L,43733L,43734L,43735L,43736L,43737L,43738L,43739L,43740L,
8828443741L,43742L,43743L,43744L,43745L,43746L,43747L,43748L,43749L,43750L,
8828543751L,43752L,43753L,43754L,43755L,43756L,43757L,43758L,43759L,43760L,
8828643761L,43762L,43763L,43764L,43765L,43766L,43767L,43768L,43769L,43770L,
8828743771L,43772L,43773L,43774L,43775L,43776L,43777L,43778L,43779L,43780L,
8828843781L,43782L,43783L,43784L,43785L,43786L,43787L,43788L,43789L,43790L,
8828943791L,43792L,43793L,43794L,43795L,43796L,43797L,43798L,43799L,43800L,
8829043801L,43802L,43803L,43804L,43805L,43806L,43807L,43808L,43809L,43810L,
8829143811L,43812L,43813L,43814L,43815L,43816L,43817L,43818L,43819L,43820L,
8829243821L,43822L,43823L,43824L,43825L,43826L,43827L,43828L,43829L,43830L,
8829343831L,43832L,43833L,43834L,43835L,43836L,43837L,43838L,43839L,43840L,
8829443841L,43842L,43843L,43844L,43845L,43846L,43847L,43848L,43849L,43850L,
8829543851L,43852L,43853L,43854L,43855L,43856L,43857L,43858L,42931L,43860L,
8829643861L,43862L,43863L,43864L,43865L,43866L,43867L,43868L,43869L,43870L,
8829743871L,43872L,43873L,43874L,43875L,43876L,43877L,43878L,43879L,43880L,
8829843881L,43882L,43883L,43884L,43885L,43886L,43887L,5024,5025,5026,5027,5028,
882995029,5030,5031,5032,5033,5034,5035,5036,5037,5038,5039,5040,5041,5042,5043,
883005044,5045,5046,5047,5048,5049,5050,5051,5052,5053,5054,5055,5056,5057,5058,
883015059,5060,5061,5062,5063,5064,5065,5066,5067,5068,5069,5070,5071,5072,5073,
883025074,5075,5076,5077,5078,5079,5080,5081,5082,5083,5084,5085,5086,5087,5088,
883035089,5090,5091,5092,5093,5094,5095,5096,5097,5098,5099,5100,5101,5102,5103,
8830443968L,43969L,43970L,43971L,43972L,43973L,43974L,43975L,43976L,43977L,
8830543978L,43979L,43980L,43981L,43982L,43983L,43984L,43985L,43986L,43987L,
8830643988L,43989L,43990L,43991L,43992L,43993L,43994L,43995L,43996L,43997L,
8830743998L,43999L,44000L,44001L,44002L,44003L,44004L,44005L,44006L,44007L,
8830844008L,44009L,44010L,44011L,44012L,44013L,44014L,44015L,44016L,44017L,
8830944018L,44019L,44020L,44021L,44022L,44023L,44024L,44025L,44026L,44027L,
8831044028L,44029L,44030L,44031L,44032L,44033L,44034L,44035L,44036L,44037L,
8831144038L,44039L,44040L,44041L,44042L,44043L,44044L,44045L,44046L,44047L,
8831244048L,44049L,44050L,44051L,44052L,44053L,44054L,44055L,44056L,44057L,
8831344058L,44059L,44060L,44061L,44062L,44063L,44064L,44065L,44066L,44067L,
8831444068L,44069L,44070L,44071L,44072L,44073L,44074L,44075L,44076L,44077L,
8831544078L,44079L,44080L,44081L,44082L,44083L,44084L,44085L,44086L,44087L,
8831644088L,44089L,44090L,44091L,44092L,44093L,44094L,44095L,44096L,44097L,
8831744098L,44099L,44100L,44101L,44102L,44103L,44104L,44105L,44106L,44107L,
8831844108L,44109L,44110L,44111L,44112L,44113L,44114L,44115L,44116L,44117L,
8831944118L,44119L,44120L,44121L,44122L,44123L,44124L,44125L,44126L,44127L,
8832044128L,44129L,44130L,44131L,44132L,44133L,44134L,44135L,44136L,44137L,
8832144138L,44139L,44140L,44141L,44142L,44143L,44144L,44145L,44146L,44147L,
8832244148L,44149L,44150L,44151L,44152L,44153L,44154L,44155L,44156L,44157L,
8832344158L,44159L,44160L,44161L,44162L,44163L,44164L,44165L,44166L,44167L,
8832444168L,44169L,44170L,44171L,44172L,44173L,44174L,44175L,44176L,44177L,
8832544178L,44179L,44180L,44181L,44182L,44183L,44184L,44185L,44186L,44187L,
8832644188L,44189L,44190L,44191L,44192L,44193L,44194L,44195L,44196L,44197L,
8832744198L,44199L,44200L,44201L,44202L,44203L,44204L,44205L,44206L,44207L,
8832844208L,44209L,44210L,44211L,44212L,44213L,44214L,44215L,44216L,44217L,
8832944218L,44219L,44220L,44221L,44222L,44223L,44224L,44225L,44226L,44227L,
8833044228L,44229L,44230L,44231L,44232L,44233L,44234L,44235L,44236L,44237L,
8833144238L,44239L,44240L,44241L,44242L,44243L,44244L,44245L,44246L,44247L,
8833244248L,44249L,44250L,44251L,44252L,44253L,44254L,44255L,44256L,44257L,
8833344258L,44259L,44260L,44261L,44262L,44263L,44264L,44265L,44266L,44267L,
8833444268L,44269L,44270L,44271L,44272L,44273L,44274L,44275L,44276L,44277L,
8833544278L,44279L,44280L,44281L,44282L,44283L,44284L,44285L,44286L,44287L,
8833644288L,44289L,44290L,44291L,44292L,44293L,44294L,44295L,44296L,44297L,
8833744298L,44299L,44300L,44301L,44302L,44303L,44304L,44305L,44306L,44307L,
8833844308L,44309L,44310L,44311L,44312L,44313L,44314L,44315L,44316L,44317L,
8833944318L,44319L,44320L,44321L,44322L,44323L,44324L,44325L,44326L,44327L,
8834044328L,44329L,44330L,44331L,44332L,44333L,44334L,44335L,44336L,44337L,
8834144338L,44339L,44340L,44341L,44342L,44343L,44344L,44345L,44346L,44347L,
8834244348L,44349L,44350L,44351L,44352L,44353L,44354L,44355L,44356L,44357L,
8834344358L,44359L,44360L,44361L,44362L,44363L,44364L,44365L,44366L,44367L,
8834444368L,44369L,44370L,44371L,44372L,44373L,44374L,44375L,44376L,44377L,
8834544378L,44379L,44380L,44381L,44382L,44383L,44384L,44385L,44386L,44387L,
8834644388L,44389L,44390L,44391L,44392L,44393L,44394L,44395L,44396L,44397L,
8834744398L,44399L,44400L,44401L,44402L,44403L,44404L,44405L,44406L,44407L,
8834844408L,44409L,44410L,44411L,44412L,44413L,44414L,44415L,44416L,44417L,
8834944418L,44419L,44420L,44421L,44422L,44423L,44424L,44425L,44426L,44427L,
8835044428L,44429L,44430L,44431L,44432L,44433L,44434L,44435L,44436L,44437L,
8835144438L,44439L,44440L,44441L,44442L,44443L,44444L,44445L,44446L,44447L,
8835244448L,44449L,44450L,44451L,44452L,44453L,44454L,44455L,44456L,44457L,
8835344458L,44459L,44460L,44461L,44462L,44463L,44464L,44465L,44466L,44467L,
8835444468L,44469L,44470L,44471L,44472L,44473L,44474L,44475L,44476L,44477L,
8835544478L,44479L,44480L,44481L,44482L,44483L,44484L,44485L,44486L,44487L,
8835644488L,44489L,44490L,44491L,44492L,44493L,44494L,44495L,44496L,44497L,
8835744498L,44499L,44500L,44501L,44502L,44503L,44504L,44505L,44506L,44507L,
8835844508L,44509L,44510L,44511L,44512L,44513L,44514L,44515L,44516L,44517L,
8835944518L,44519L,44520L,44521L,44522L,44523L,44524L,44525L,44526L,44527L,
8836044528L,44529L,44530L,44531L,44532L,44533L,44534L,44535L,44536L,44537L,
8836144538L,44539L,44540L,44541L,44542L,44543L,44544L,44545L,44546L,44547L,
8836244548L,44549L,44550L,44551L,44552L,44553L,44554L,44555L,44556L,44557L,
8836344558L,44559L,44560L,44561L,44562L,44563L,44564L,44565L,44566L,44567L,
8836444568L,44569L,44570L,44571L,44572L,44573L,44574L,44575L,44576L,44577L,
8836544578L,44579L,44580L,44581L,44582L,44583L,44584L,44585L,44586L,44587L,
8836644588L,44589L,44590L,44591L,44592L,44593L,44594L,44595L,44596L,44597L,
8836744598L,44599L,44600L,44601L,44602L,44603L,44604L,44605L,44606L,44607L,
8836844608L,44609L,44610L,44611L,44612L,44613L,44614L,44615L,44616L,44617L,
8836944618L,44619L,44620L,44621L,44622L,44623L,44624L,44625L,44626L,44627L,
8837044628L,44629L,44630L,44631L,44632L,44633L,44634L,44635L,44636L,44637L,
8837144638L,44639L,44640L,44641L,44642L,44643L,44644L,44645L,44646L,44647L,
8837244648L,44649L,44650L,44651L,44652L,44653L,44654L,44655L,44656L,44657L,
8837344658L,44659L,44660L,44661L,44662L,44663L,44664L,44665L,44666L,44667L,
8837444668L,44669L,44670L,44671L,44672L,44673L,44674L,44675L,44676L,44677L,
8837544678L,44679L,44680L,44681L,44682L,44683L,44684L,44685L,44686L,44687L,
8837644688L,44689L,44690L,44691L,44692L,44693L,44694L,44695L,44696L,44697L,
8837744698L,44699L,44700L,44701L,44702L,44703L,44704L,44705L,44706L,44707L,
8837844708L,44709L,44710L,44711L,44712L,44713L,44714L,44715L,44716L,44717L,
8837944718L,44719L,44720L,44721L,44722L,44723L,44724L,44725L,44726L,44727L,
8838044728L,44729L,44730L,44731L,44732L,44733L,44734L,44735L,44736L,44737L,
8838144738L,44739L,44740L,44741L,44742L,44743L,44744L,44745L,44746L,44747L,
8838244748L,44749L,44750L,44751L,44752L,44753L,44754L,44755L,44756L,44757L,
8838344758L,44759L,44760L,44761L,44762L,44763L,44764L,44765L,44766L,44767L,
8838444768L,44769L,44770L,44771L,44772L,44773L,44774L,44775L,44776L,44777L,
8838544778L,44779L,44780L,44781L,44782L,44783L,44784L,44785L,44786L,44787L,
8838644788L,44789L,44790L,44791L,44792L,44793L,44794L,44795L,44796L,44797L,
8838744798L,44799L,44800L,44801L,44802L,44803L,44804L,44805L,44806L,44807L,
8838844808L,44809L,44810L,44811L,44812L,44813L,44814L,44815L,44816L,44817L,
8838944818L,44819L,44820L,44821L,44822L,44823L,44824L,44825L,44826L,44827L,
8839044828L,44829L,44830L,44831L,44832L,44833L,44834L,44835L,44836L,44837L,
8839144838L,44839L,44840L,44841L,44842L,44843L,44844L,44845L,44846L,44847L,
8839244848L,44849L,44850L,44851L,44852L,44853L,44854L,44855L,44856L,44857L,
8839344858L,44859L,44860L,44861L,44862L,44863L,44864L,44865L,44866L,44867L,
8839444868L,44869L,44870L,44871L,44872L,44873L,44874L,44875L,44876L,44877L,
8839544878L,44879L,44880L,44881L,44882L,44883L,44884L,44885L,44886L,44887L,
8839644888L,44889L,44890L,44891L,44892L,44893L,44894L,44895L,44896L,44897L,
8839744898L,44899L,44900L,44901L,44902L,44903L,44904L,44905L,44906L,44907L,
8839844908L,44909L,44910L,44911L,44912L,44913L,44914L,44915L,44916L,44917L,
8839944918L,44919L,44920L,44921L,44922L,44923L,44924L,44925L,44926L,44927L,
8840044928L,44929L,44930L,44931L,44932L,44933L,44934L,44935L,44936L,44937L,
8840144938L,44939L,44940L,44941L,44942L,44943L,44944L,44945L,44946L,44947L,
8840244948L,44949L,44950L,44951L,44952L,44953L,44954L,44955L,44956L,44957L,
8840344958L,44959L,44960L,44961L,44962L,44963L,44964L,44965L,44966L,44967L,
8840444968L,44969L,44970L,44971L,44972L,44973L,44974L,44975L,44976L,44977L,
8840544978L,44979L,44980L,44981L,44982L,44983L,44984L,44985L,44986L,44987L,
8840644988L,44989L,44990L,44991L,44992L,44993L,44994L,44995L,44996L,44997L,
8840744998L,44999L,45000L,45001L,45002L,45003L,45004L,45005L,45006L,45007L,
8840845008L,45009L,45010L,45011L,45012L,45013L,45014L,45015L,45016L,45017L,
8840945018L,45019L,45020L,45021L,45022L,45023L,45024L,45025L,45026L,45027L,
8841045028L,45029L,45030L,45031L,45032L,45033L,45034L,45035L,45036L,45037L,
8841145038L,45039L,45040L,45041L,45042L,45043L,45044L,45045L,45046L,45047L,
8841245048L,45049L,45050L,45051L,45052L,45053L,45054L,45055L,45056L,45057L,
8841345058L,45059L,45060L,45061L,45062L,45063L,45064L,45065L,45066L,45067L,
8841445068L,45069L,45070L,45071L,45072L,45073L,45074L,45075L,45076L,45077L,
8841545078L,45079L,45080L,45081L,45082L,45083L,45084L,45085L,45086L,45087L,
8841645088L,45089L,45090L,45091L,45092L,45093L,45094L,45095L,45096L,45097L,
8841745098L,45099L,45100L,45101L,45102L,45103L,45104L,45105L,45106L,45107L,
8841845108L,45109L,45110L,45111L,45112L,45113L,45114L,45115L,45116L,45117L,
8841945118L,45119L,45120L,45121L,45122L,45123L,45124L,45125L,45126L,45127L,
8842045128L,45129L,45130L,45131L,45132L,45133L,45134L,45135L,45136L,45137L,
8842145138L,45139L,45140L,45141L,45142L,45143L,45144L,45145L,45146L,45147L,
8842245148L,45149L,45150L,45151L,45152L,45153L,45154L,45155L,45156L,45157L,
8842345158L,45159L,45160L,45161L,45162L,45163L,45164L,45165L,45166L,45167L,
8842445168L,45169L,45170L,45171L,45172L,45173L,45174L,45175L,45176L,45177L,
8842545178L,45179L,45180L,45181L,45182L,45183L,45184L,45185L,45186L,45187L,
8842645188L,45189L,45190L,45191L,45192L,45193L,45194L,45195L,45196L,45197L,
8842745198L,45199L,45200L,45201L,45202L,45203L,45204L,45205L,45206L,45207L,
8842845208L,45209L,45210L,45211L,45212L,45213L,45214L,45215L,45216L,45217L,
8842945218L,45219L,45220L,45221L,45222L,45223L,45224L,45225L,45226L,45227L,
8843045228L,45229L,45230L,45231L,45232L,45233L,45234L,45235L,45236L,45237L,
8843145238L,45239L,45240L,45241L,45242L,45243L,45244L,45245L,45246L,45247L,
8843245248L,45249L,45250L,45251L,45252L,45253L,45254L,45255L,45256L,45257L,
8843345258L,45259L,45260L,45261L,45262L,45263L,45264L,45265L,45266L,45267L,
8843445268L,45269L,45270L,45271L,45272L,45273L,45274L,45275L,45276L,45277L,
8843545278L,45279L,45280L,45281L,45282L,45283L,45284L,45285L,45286L,45287L,
8843645288L,45289L,45290L,45291L,45292L,45293L,45294L,45295L,45296L,45297L,
8843745298L,45299L,45300L,45301L,45302L,45303L,45304L,45305L,45306L,45307L,
8843845308L,45309L,45310L,45311L,45312L,45313L,45314L,45315L,45316L,45317L,
8843945318L,45319L,45320L,45321L,45322L,45323L,45324L,45325L,45326L,45327L,
8844045328L,45329L,45330L,45331L,45332L,45333L,45334L,45335L,45336L,45337L,
8844145338L,45339L,45340L,45341L,45342L,45343L,45344L,45345L,45346L,45347L,
8844245348L,45349L,45350L,45351L,45352L,45353L,45354L,45355L,45356L,45357L,
8844345358L,45359L,45360L,45361L,45362L,45363L,45364L,45365L,45366L,45367L,
8844445368L,45369L,45370L,45371L,45372L,45373L,45374L,45375L,45376L,45377L,
8844545378L,45379L,45380L,45381L,45382L,45383L,45384L,45385L,45386L,45387L,
8844645388L,45389L,45390L,45391L,45392L,45393L,45394L,45395L,45396L,45397L,
8844745398L,45399L,45400L,45401L,45402L,45403L,45404L,45405L,45406L,45407L,
8844845408L,45409L,45410L,45411L,45412L,45413L,45414L,45415L,45416L,45417L,
8844945418L,45419L,45420L,45421L,45422L,45423L,45424L,45425L,45426L,45427L,
8845045428L,45429L,45430L,45431L,45432L,45433L,45434L,45435L,45436L,45437L,
8845145438L,45439L,45440L,45441L,45442L,45443L,45444L,45445L,45446L,45447L,
8845245448L,45449L,45450L,45451L,45452L,45453L,45454L,45455L,45456L,45457L,
8845345458L,45459L,45460L,45461L,45462L,45463L,45464L,45465L,45466L,45467L,
8845445468L,45469L,45470L,45471L,45472L,45473L,45474L,45475L,45476L,45477L,
8845545478L,45479L,45480L,45481L,45482L,45483L,45484L,45485L,45486L,45487L,
8845645488L,45489L,45490L,45491L,45492L,45493L,45494L,45495L,45496L,45497L,
8845745498L,45499L,45500L,45501L,45502L,45503L,45504L,45505L,45506L,45507L,
8845845508L,45509L,45510L,45511L,45512L,45513L,45514L,45515L,45516L,45517L,
8845945518L,45519L,45520L,45521L,45522L,45523L,45524L,45525L,45526L,45527L,
8846045528L,45529L,45530L,45531L,45532L,45533L,45534L,45535L,45536L,45537L,
8846145538L,45539L,45540L,45541L,45542L,45543L,45544L,45545L,45546L,45547L,
8846245548L,45549L,45550L,45551L,45552L,45553L,45554L,45555L,45556L,45557L,
8846345558L,45559L,45560L,45561L,45562L,45563L,45564L,45565L,45566L,45567L,
8846445568L,45569L,45570L,45571L,45572L,45573L,45574L,45575L,45576L,45577L,
8846545578L,45579L,45580L,45581L,45582L,45583L,45584L,45585L,45586L,45587L,
8846645588L,45589L,45590L,45591L,45592L,45593L,45594L,45595L,45596L,45597L,
8846745598L,45599L,45600L,45601L,45602L,45603L,45604L,45605L,45606L,45607L,
8846845608L,45609L,45610L,45611L,45612L,45613L,45614L,45615L,45616L,45617L,
8846945618L,45619L,45620L,45621L,45622L,45623L,45624L,45625L,45626L,45627L,
8847045628L,45629L,45630L,45631L,45632L,45633L,45634L,45635L,45636L,45637L,
8847145638L,45639L,45640L,45641L,45642L,45643L,45644L,45645L,45646L,45647L,
8847245648L,45649L,45650L,45651L,45652L,45653L,45654L,45655L,45656L,45657L,
8847345658L,45659L,45660L,45661L,45662L,45663L,45664L,45665L,45666L,45667L,
8847445668L,45669L,45670L,45671L,45672L,45673L,45674L,45675L,45676L,45677L,
8847545678L,45679L,45680L,45681L,45682L,45683L,45684L,45685L,45686L,45687L,
8847645688L,45689L,45690L,45691L,45692L,45693L,45694L,45695L,45696L,45697L,
8847745698L,45699L,45700L,45701L,45702L,45703L,45704L,45705L,45706L,45707L,
8847845708L,45709L,45710L,45711L,45712L,45713L,45714L,45715L,45716L,45717L,
8847945718L,45719L,45720L,45721L,45722L,45723L,45724L,45725L,45726L,45727L,
8848045728L,45729L,45730L,45731L,45732L,45733L,45734L,45735L,45736L,45737L,
8848145738L,45739L,45740L,45741L,45742L,45743L,45744L,45745L,45746L,45747L,
8848245748L,45749L,45750L,45751L,45752L,45753L,45754L,45755L,45756L,45757L,
8848345758L,45759L,45760L,45761L,45762L,45763L,45764L,45765L,45766L,45767L,
8848445768L,45769L,45770L,45771L,45772L,45773L,45774L,45775L,45776L,45777L,
8848545778L,45779L,45780L,45781L,45782L,45783L,45784L,45785L,45786L,45787L,
8848645788L,45789L,45790L,45791L,45792L,45793L,45794L,45795L,45796L,45797L,
8848745798L,45799L,45800L,45801L,45802L,45803L,45804L,45805L,45806L,45807L,
8848845808L,45809L,45810L,45811L,45812L,45813L,45814L,45815L,45816L,45817L,
8848945818L,45819L,45820L,45821L,45822L,45823L,45824L,45825L,45826L,45827L,
8849045828L,45829L,45830L,45831L,45832L,45833L,45834L,45835L,45836L,45837L,
8849145838L,45839L,45840L,45841L,45842L,45843L,45844L,45845L,45846L,45847L,
8849245848L,45849L,45850L,45851L,45852L,45853L,45854L,45855L,45856L,45857L,
8849345858L,45859L,45860L,45861L,45862L,45863L,45864L,45865L,45866L,45867L,
8849445868L,45869L,45870L,45871L,45872L,45873L,45874L,45875L,45876L,45877L,
8849545878L,45879L,45880L,45881L,45882L,45883L,45884L,45885L,45886L,45887L,
8849645888L,45889L,45890L,45891L,45892L,45893L,45894L,45895L,45896L,45897L,
8849745898L,45899L,45900L,45901L,45902L,45903L,45904L,45905L,45906L,45907L,
8849845908L,45909L,45910L,45911L,45912L,45913L,45914L,45915L,45916L,45917L,
8849945918L,45919L,45920L,45921L,45922L,45923L,45924L,45925L,45926L,45927L,
8850045928L,45929L,45930L,45931L,45932L,45933L,45934L,45935L,45936L,45937L,
8850145938L,45939L,45940L,45941L,45942L,45943L,45944L,45945L,45946L,45947L,
8850245948L,45949L,45950L,45951L,45952L,45953L,45954L,45955L,45956L,45957L,
8850345958L,45959L,45960L,45961L,45962L,45963L,45964L,45965L,45966L,45967L,
8850445968L,45969L,45970L,45971L,45972L,45973L,45974L,45975L,45976L,45977L,
8850545978L,45979L,45980L,45981L,45982L,45983L,45984L,45985L,45986L,45987L,
8850645988L,45989L,45990L,45991L,45992L,45993L,45994L,45995L,45996L,45997L,
8850745998L,45999L,46000L,46001L,46002L,46003L,46004L,46005L,46006L,46007L,
8850846008L,46009L,46010L,46011L,46012L,46013L,46014L,46015L,46016L,46017L,
8850946018L,46019L,46020L,46021L,46022L,46023L,46024L,46025L,46026L,46027L,
8851046028L,46029L,46030L,46031L,46032L,46033L,46034L,46035L,46036L,46037L,
8851146038L,46039L,46040L,46041L,46042L,46043L,46044L,46045L,46046L,46047L,
8851246048L,46049L,46050L,46051L,46052L,46053L,46054L,46055L,46056L,46057L,
8851346058L,46059L,46060L,46061L,46062L,46063L,46064L,46065L,46066L,46067L,
8851446068L,46069L,46070L,46071L,46072L,46073L,46074L,46075L,46076L,46077L,
8851546078L,46079L,46080L,46081L,46082L,46083L,46084L,46085L,46086L,46087L,
8851646088L,46089L,46090L,46091L,46092L,46093L,46094L,46095L,46096L,46097L,
8851746098L,46099L,46100L,46101L,46102L,46103L,46104L,46105L,46106L,46107L,
8851846108L,46109L,46110L,46111L,46112L,46113L,46114L,46115L,46116L,46117L,
8851946118L,46119L,46120L,46121L,46122L,46123L,46124L,46125L,46126L,46127L,
8852046128L,46129L,46130L,46131L,46132L,46133L,46134L,46135L,46136L,46137L,
8852146138L,46139L,46140L,46141L,46142L,46143L,46144L,46145L,46146L,46147L,
8852246148L,46149L,46150L,46151L,46152L,46153L,46154L,46155L,46156L,46157L,
8852346158L,46159L,46160L,46161L,46162L,46163L,46164L,46165L,46166L,46167L,
8852446168L,46169L,46170L,46171L,46172L,46173L,46174L,46175L,46176L,46177L,
8852546178L,46179L,46180L,46181L,46182L,46183L,46184L,46185L,46186L,46187L,
8852646188L,46189L,46190L,46191L,46192L,46193L,46194L,46195L,46196L,46197L,
8852746198L,46199L,46200L,46201L,46202L,46203L,46204L,46205L,46206L,46207L,
8852846208L,46209L,46210L,46211L,46212L,46213L,46214L,46215L,46216L,46217L,
8852946218L,46219L,46220L,46221L,46222L,46223L,46224L,46225L,46226L,46227L,
8853046228L,46229L,46230L,46231L,46232L,46233L,46234L,46235L,46236L,46237L,
8853146238L,46239L,46240L,46241L,46242L,46243L,46244L,46245L,46246L,46247L,
8853246248L,46249L,46250L,46251L,46252L,46253L,46254L,46255L,46256L,46257L,
8853346258L,46259L,46260L,46261L,46262L,46263L,46264L,46265L,46266L,46267L,
8853446268L,46269L,46270L,46271L,46272L,46273L,46274L,46275L,46276L,46277L,
8853546278L,46279L,46280L,46281L,46282L,46283L,46284L,46285L,46286L,46287L,
8853646288L,46289L,46290L,46291L,46292L,46293L,46294L,46295L,46296L,46297L,
8853746298L,46299L,46300L,46301L,46302L,46303L,46304L,46305L,46306L,46307L,
8853846308L,46309L,46310L,46311L,46312L,46313L,46314L,46315L,46316L,46317L,
8853946318L,46319L,46320L,46321L,46322L,46323L,46324L,46325L,46326L,46327L,
8854046328L,46329L,46330L,46331L,46332L,46333L,46334L,46335L,46336L,46337L,
8854146338L,46339L,46340L,46341L,46342L,46343L,46344L,46345L,46346L,46347L,
8854246348L,46349L,46350L,46351L,46352L,46353L,46354L,46355L,46356L,46357L,
8854346358L,46359L,46360L,46361L,46362L,46363L,46364L,46365L,46366L,46367L,
8854446368L,46369L,46370L,46371L,46372L,46373L,46374L,46375L,46376L,46377L,
8854546378L,46379L,46380L,46381L,46382L,46383L,46384L,46385L,46386L,46387L,
8854646388L,46389L,46390L,46391L,46392L,46393L,46394L,46395L,46396L,46397L,
8854746398L,46399L,46400L,46401L,46402L,46403L,46404L,46405L,46406L,46407L,
8854846408L,46409L,46410L,46411L,46412L,46413L,46414L,46415L,46416L,46417L,
8854946418L,46419L,46420L,46421L,46422L,46423L,46424L,46425L,46426L,46427L,
8855046428L,46429L,46430L,46431L,46432L,46433L,46434L,46435L,46436L,46437L,
8855146438L,46439L,46440L,46441L,46442L,46443L,46444L,46445L,46446L,46447L,
8855246448L,46449L,46450L,46451L,46452L,46453L,46454L,46455L,46456L,46457L,
8855346458L,46459L,46460L,46461L,46462L,46463L,46464L,46465L,46466L,46467L,
8855446468L,46469L,46470L,46471L,46472L,46473L,46474L,46475L,46476L,46477L,
8855546478L,46479L,46480L,46481L,46482L,46483L,46484L,46485L,46486L,46487L,
8855646488L,46489L,46490L,46491L,46492L,46493L,46494L,46495L,46496L,46497L,
8855746498L,46499L,46500L,46501L,46502L,46503L,46504L,46505L,46506L,46507L,
8855846508L,46509L,46510L,46511L,46512L,46513L,46514L,46515L,46516L,46517L,
8855946518L,46519L,46520L,46521L,46522L,46523L,46524L,46525L,46526L,46527L,
8856046528L,46529L,46530L,46531L,46532L,46533L,46534L,46535L,46536L,46537L,
8856146538L,46539L,46540L,46541L,46542L,46543L,46544L,46545L,46546L,46547L,
8856246548L,46549L,46550L,46551L,46552L,46553L,46554L,46555L,46556L,46557L,
8856346558L,46559L,46560L,46561L,46562L,46563L,46564L,46565L,46566L,46567L,
8856446568L,46569L,46570L,46571L,46572L,46573L,46574L,46575L,46576L,46577L,
8856546578L,46579L,46580L,46581L,46582L,46583L,46584L,46585L,46586L,46587L,
8856646588L,46589L,46590L,46591L,46592L,46593L,46594L,46595L,46596L,46597L,
8856746598L,46599L,46600L,46601L,46602L,46603L,46604L,46605L,46606L,46607L,
8856846608L,46609L,46610L,46611L,46612L,46613L,46614L,46615L,46616L,46617L,
8856946618L,46619L,46620L,46621L,46622L,46623L,46624L,46625L,46626L,46627L,
8857046628L,46629L,46630L,46631L,46632L,46633L,46634L,46635L,46636L,46637L,
8857146638L,46639L,46640L,46641L,46642L,46643L,46644L,46645L,46646L,46647L,
8857246648L,46649L,46650L,46651L,46652L,46653L,46654L,46655L,46656L,46657L,
8857346658L,46659L,46660L,46661L,46662L,46663L,46664L,46665L,46666L,46667L,
8857446668L,46669L,46670L,46671L,46672L,46673L,46674L,46675L,46676L,46677L,
8857546678L,46679L,46680L,46681L,46682L,46683L,46684L,46685L,46686L,46687L,
8857646688L,46689L,46690L,46691L,46692L,46693L,46694L,46695L,46696L,46697L,
8857746698L,46699L,46700L,46701L,46702L,46703L,46704L,46705L,46706L,46707L,
8857846708L,46709L,46710L,46711L,46712L,46713L,46714L,46715L,46716L,46717L,
8857946718L,46719L,46720L,46721L,46722L,46723L,46724L,46725L,46726L,46727L,
8858046728L,46729L,46730L,46731L,46732L,46733L,46734L,46735L,46736L,46737L,
8858146738L,46739L,46740L,46741L,46742L,46743L,46744L,46745L,46746L,46747L,
8858246748L,46749L,46750L,46751L,46752L,46753L,46754L,46755L,46756L,46757L,
8858346758L,46759L,46760L,46761L,46762L,46763L,46764L,46765L,46766L,46767L,
8858446768L,46769L,46770L,46771L,46772L,46773L,46774L,46775L,46776L,46777L,
8858546778L,46779L,46780L,46781L,46782L,46783L,46784L,46785L,46786L,46787L,
8858646788L,46789L,46790L,46791L,46792L,46793L,46794L,46795L,46796L,46797L,
8858746798L,46799L,46800L,46801L,46802L,46803L,46804L,46805L,46806L,46807L,
8858846808L,46809L,46810L,46811L,46812L,46813L,46814L,46815L,46816L,46817L,
8858946818L,46819L,46820L,46821L,46822L,46823L,46824L,46825L,46826L,46827L,
8859046828L,46829L,46830L,46831L,46832L,46833L,46834L,46835L,46836L,46837L,
8859146838L,46839L,46840L,46841L,46842L,46843L,46844L,46845L,46846L,46847L,
8859246848L,46849L,46850L,46851L,46852L,46853L,46854L,46855L,46856L,46857L,
8859346858L,46859L,46860L,46861L,46862L,46863L,46864L,46865L,46866L,46867L,
8859446868L,46869L,46870L,46871L,46872L,46873L,46874L,46875L,46876L,46877L,
8859546878L,46879L,46880L,46881L,46882L,46883L,46884L,46885L,46886L,46887L,
8859646888L,46889L,46890L,46891L,46892L,46893L,46894L,46895L,46896L,46897L,
8859746898L,46899L,46900L,46901L,46902L,46903L,46904L,46905L,46906L,46907L,
8859846908L,46909L,46910L,46911L,46912L,46913L,46914L,46915L,46916L,46917L,
8859946918L,46919L,46920L,46921L,46922L,46923L,46924L,46925L,46926L,46927L,
8860046928L,46929L,46930L,46931L,46932L,46933L,46934L,46935L,46936L,46937L,
8860146938L,46939L,46940L,46941L,46942L,46943L,46944L,46945L,46946L,46947L,
8860246948L,46949L,46950L,46951L,46952L,46953L,46954L,46955L,46956L,46957L,
8860346958L,46959L,46960L,46961L,46962L,46963L,46964L,46965L,46966L,46967L,
8860446968L,46969L,46970L,46971L,46972L,46973L,46974L,46975L,46976L,46977L,
8860546978L,46979L,46980L,46981L,46982L,46983L,46984L,46985L,46986L,46987L,
8860646988L,46989L,46990L,46991L,46992L,46993L,46994L,46995L,46996L,46997L,
8860746998L,46999L,47000L,47001L,47002L,47003L,47004L,47005L,47006L,47007L,
8860847008L,47009L,47010L,47011L,47012L,47013L,47014L,47015L,47016L,47017L,
8860947018L,47019L,47020L,47021L,47022L,47023L,47024L,47025L,47026L,47027L,
8861047028L,47029L,47030L,47031L,47032L,47033L,47034L,47035L,47036L,47037L,
8861147038L,47039L,47040L,47041L,47042L,47043L,47044L,47045L,47046L,47047L,
8861247048L,47049L,47050L,47051L,47052L,47053L,47054L,47055L,47056L,47057L,
8861347058L,47059L,47060L,47061L,47062L,47063L,47064L,47065L,47066L,47067L,
8861447068L,47069L,47070L,47071L,47072L,47073L,47074L,47075L,47076L,47077L,
8861547078L,47079L,47080L,47081L,47082L,47083L,47084L,47085L,47086L,47087L,
8861647088L,47089L,47090L,47091L,47092L,47093L,47094L,47095L,47096L,47097L,
8861747098L,47099L,47100L,47101L,47102L,47103L,47104L,47105L,47106L,47107L,
8861847108L,47109L,47110L,47111L,47112L,47113L,47114L,47115L,47116L,47117L,
8861947118L,47119L,47120L,47121L,47122L,47123L,47124L,47125L,47126L,47127L,
8862047128L,47129L,47130L,47131L,47132L,47133L,47134L,47135L,47136L,47137L,
8862147138L,47139L,47140L,47141L,47142L,47143L,47144L,47145L,47146L,47147L,
8862247148L,47149L,47150L,47151L,47152L,47153L,47154L,47155L,47156L,47157L,
8862347158L,47159L,47160L,47161L,47162L,47163L,47164L,47165L,47166L,47167L,
8862447168L,47169L,47170L,47171L,47172L,47173L,47174L,47175L,47176L,47177L,
8862547178L,47179L,47180L,47181L,47182L,47183L,47184L,47185L,47186L,47187L,
8862647188L,47189L,47190L,47191L,47192L,47193L,47194L,47195L,47196L,47197L,
8862747198L,47199L,47200L,47201L,47202L,47203L,47204L,47205L,47206L,47207L,
8862847208L,47209L,47210L,47211L,47212L,47213L,47214L,47215L,47216L,47217L,
8862947218L,47219L,47220L,47221L,47222L,47223L,47224L,47225L,47226L,47227L,
8863047228L,47229L,47230L,47231L,47232L,47233L,47234L,47235L,47236L,47237L,
8863147238L,47239L,47240L,47241L,47242L,47243L,47244L,47245L,47246L,47247L,
8863247248L,47249L,47250L,47251L,47252L,47253L,47254L,47255L,47256L,47257L,
8863347258L,47259L,47260L,47261L,47262L,47263L,47264L,47265L,47266L,47267L,
8863447268L,47269L,47270L,47271L,47272L,47273L,47274L,47275L,47276L,47277L,
8863547278L,47279L,47280L,47281L,47282L,47283L,47284L,47285L,47286L,47287L,
8863647288L,47289L,47290L,47291L,47292L,47293L,47294L,47295L,47296L,47297L,
8863747298L,47299L,47300L,47301L,47302L,47303L,47304L,47305L,47306L,47307L,
8863847308L,47309L,47310L,47311L,47312L,47313L,47314L,47315L,47316L,47317L,
8863947318L,47319L,47320L,47321L,47322L,47323L,47324L,47325L,47326L,47327L,
8864047328L,47329L,47330L,47331L,47332L,47333L,47334L,47335L,47336L,47337L,
8864147338L,47339L,47340L,47341L,47342L,47343L,47344L,47345L,47346L,47347L,
8864247348L,47349L,47350L,47351L,47352L,47353L,47354L,47355L,47356L,47357L,
8864347358L,47359L,47360L,47361L,47362L,47363L,47364L,47365L,47366L,47367L,
8864447368L,47369L,47370L,47371L,47372L,47373L,47374L,47375L,47376L,47377L,
8864547378L,47379L,47380L,47381L,47382L,47383L,47384L,47385L,47386L,47387L,
8864647388L,47389L,47390L,47391L,47392L,47393L,47394L,47395L,47396L,47397L,
8864747398L,47399L,47400L,47401L,47402L,47403L,47404L,47405L,47406L,47407L,
8864847408L,47409L,47410L,47411L,47412L,47413L,47414L,47415L,47416L,47417L,
8864947418L,47419L,47420L,47421L,47422L,47423L,47424L,47425L,47426L,47427L,
8865047428L,47429L,47430L,47431L,47432L,47433L,47434L,47435L,47436L,47437L,
8865147438L,47439L,47440L,47441L,47442L,47443L,47444L,47445L,47446L,47447L,
8865247448L,47449L,47450L,47451L,47452L,47453L,47454L,47455L,47456L,47457L,
8865347458L,47459L,47460L,47461L,47462L,47463L,47464L,47465L,47466L,47467L,
8865447468L,47469L,47470L,47471L,47472L,47473L,47474L,47475L,47476L,47477L,
8865547478L,47479L,47480L,47481L,47482L,47483L,47484L,47485L,47486L,47487L,
8865647488L,47489L,47490L,47491L,47492L,47493L,47494L,47495L,47496L,47497L,
8865747498L,47499L,47500L,47501L,47502L,47503L,47504L,47505L,47506L,47507L,
8865847508L,47509L,47510L,47511L,47512L,47513L,47514L,47515L,47516L,47517L,
8865947518L,47519L,47520L,47521L,47522L,47523L,47524L,47525L,47526L,47527L,
8866047528L,47529L,47530L,47531L,47532L,47533L,47534L,47535L,47536L,47537L,
8866147538L,47539L,47540L,47541L,47542L,47543L,47544L,47545L,47546L,47547L,
8866247548L,47549L,47550L,47551L,47552L,47553L,47554L,47555L,47556L,47557L,
8866347558L,47559L,47560L,47561L,47562L,47563L,47564L,47565L,47566L,47567L,
8866447568L,47569L,47570L,47571L,47572L,47573L,47574L,47575L,47576L,47577L,
8866547578L,47579L,47580L,47581L,47582L,47583L,47584L,47585L,47586L,47587L,
8866647588L,47589L,47590L,47591L,47592L,47593L,47594L,47595L,47596L,47597L,
8866747598L,47599L,47600L,47601L,47602L,47603L,47604L,47605L,47606L,47607L,
8866847608L,47609L,47610L,47611L,47612L,47613L,47614L,47615L,47616L,47617L,
8866947618L,47619L,47620L,47621L,47622L,47623L,47624L,47625L,47626L,47627L,
8867047628L,47629L,47630L,47631L,47632L,47633L,47634L,47635L,47636L,47637L,
8867147638L,47639L,47640L,47641L,47642L,47643L,47644L,47645L,47646L,47647L,
8867247648L,47649L,47650L,47651L,47652L,47653L,47654L,47655L,47656L,47657L,
8867347658L,47659L,47660L,47661L,47662L,47663L,47664L,47665L,47666L,47667L,
8867447668L,47669L,47670L,47671L,47672L,47673L,47674L,47675L,47676L,47677L,
8867547678L,47679L,47680L,47681L,47682L,47683L,47684L,47685L,47686L,47687L,
8867647688L,47689L,47690L,47691L,47692L,47693L,47694L,47695L,47696L,47697L,
8867747698L,47699L,47700L,47701L,47702L,47703L,47704L,47705L,47706L,47707L,
8867847708L,47709L,47710L,47711L,47712L,47713L,47714L,47715L,47716L,47717L,
8867947718L,47719L,47720L,47721L,47722L,47723L,47724L,47725L,47726L,47727L,
8868047728L,47729L,47730L,47731L,47732L,47733L,47734L,47735L,47736L,47737L,
8868147738L,47739L,47740L,47741L,47742L,47743L,47744L,47745L,47746L,47747L,
8868247748L,47749L,47750L,47751L,47752L,47753L,47754L,47755L,47756L,47757L,
8868347758L,47759L,47760L,47761L,47762L,47763L,47764L,47765L,47766L,47767L,
8868447768L,47769L,47770L,47771L,47772L,47773L,47774L,47775L,47776L,47777L,
8868547778L,47779L,47780L,47781L,47782L,47783L,47784L,47785L,47786L,47787L,
8868647788L,47789L,47790L,47791L,47792L,47793L,47794L,47795L,47796L,47797L,
8868747798L,47799L,47800L,47801L,47802L,47803L,47804L,47805L,47806L,47807L,
8868847808L,47809L,47810L,47811L,47812L,47813L,47814L,47815L,47816L,47817L,
8868947818L,47819L,47820L,47821L,47822L,47823L,47824L,47825L,47826L,47827L,
8869047828L,47829L,47830L,47831L,47832L,47833L,47834L,47835L,47836L,47837L,
8869147838L,47839L,47840L,47841L,47842L,47843L,47844L,47845L,47846L,47847L,
8869247848L,47849L,47850L,47851L,47852L,47853L,47854L,47855L,47856L,47857L,
8869347858L,47859L,47860L,47861L,47862L,47863L,47864L,47865L,47866L,47867L,
8869447868L,47869L,47870L,47871L,47872L,47873L,47874L,47875L,47876L,47877L,
8869547878L,47879L,47880L,47881L,47882L,47883L,47884L,47885L,47886L,47887L,
8869647888L,47889L,47890L,47891L,47892L,47893L,47894L,47895L,47896L,47897L,
8869747898L,47899L,47900L,47901L,47902L,47903L,47904L,47905L,47906L,47907L,
8869847908L,47909L,47910L,47911L,47912L,47913L,47914L,47915L,47916L,47917L,
8869947918L,47919L,47920L,47921L,47922L,47923L,47924L,47925L,47926L,47927L,
8870047928L,47929L,47930L,47931L,47932L,47933L,47934L,47935L,47936L,47937L,
8870147938L,47939L,47940L,47941L,47942L,47943L,47944L,47945L,47946L,47947L,
8870247948L,47949L,47950L,47951L,47952L,47953L,47954L,47955L,47956L,47957L,
8870347958L,47959L,47960L,47961L,47962L,47963L,47964L,47965L,47966L,47967L,
8870447968L,47969L,47970L,47971L,47972L,47973L,47974L,47975L,47976L,47977L,
8870547978L,47979L,47980L,47981L,47982L,47983L,47984L,47985L,47986L,47987L,
8870647988L,47989L,47990L,47991L,47992L,47993L,47994L,47995L,47996L,47997L,
8870747998L,47999L,48000L,48001L,48002L,48003L,48004L,48005L,48006L,48007L,
8870848008L,48009L,48010L,48011L,48012L,48013L,48014L,48015L,48016L,48017L,
8870948018L,48019L,48020L,48021L,48022L,48023L,48024L,48025L,48026L,48027L,
8871048028L,48029L,48030L,48031L,48032L,48033L,48034L,48035L,48036L,48037L,
8871148038L,48039L,48040L,48041L,48042L,48043L,48044L,48045L,48046L,48047L,
8871248048L,48049L,48050L,48051L,48052L,48053L,48054L,48055L,48056L,48057L,
8871348058L,48059L,48060L,48061L,48062L,48063L,48064L,48065L,48066L,48067L,
8871448068L,48069L,48070L,48071L,48072L,48073L,48074L,48075L,48076L,48077L,
8871548078L,48079L,48080L,48081L,48082L,48083L,48084L,48085L,48086L,48087L,
8871648088L,48089L,48090L,48091L,48092L,48093L,48094L,48095L,48096L,48097L,
8871748098L,48099L,48100L,48101L,48102L,48103L,48104L,48105L,48106L,48107L,
8871848108L,48109L,48110L,48111L,48112L,48113L,48114L,48115L,48116L,48117L,
8871948118L,48119L,48120L,48121L,48122L,48123L,48124L,48125L,48126L,48127L,
8872048128L,48129L,48130L,48131L,48132L,48133L,48134L,48135L,48136L,48137L,
8872148138L,48139L,48140L,48141L,48142L,48143L,48144L,48145L,48146L,48147L,
8872248148L,48149L,48150L,48151L,48152L,48153L,48154L,48155L,48156L,48157L,
8872348158L,48159L,48160L,48161L,48162L,48163L,48164L,48165L,48166L,48167L,
8872448168L,48169L,48170L,48171L,48172L,48173L,48174L,48175L,48176L,48177L,
8872548178L,48179L,48180L,48181L,48182L,48183L,48184L,48185L,48186L,48187L,
8872648188L,48189L,48190L,48191L,48192L,48193L,48194L,48195L,48196L,48197L,
8872748198L,48199L,48200L,48201L,48202L,48203L,48204L,48205L,48206L,48207L,
8872848208L,48209L,48210L,48211L,48212L,48213L,48214L,48215L,48216L,48217L,
8872948218L,48219L,48220L,48221L,48222L,48223L,48224L,48225L,48226L,48227L,
8873048228L,48229L,48230L,48231L,48232L,48233L,48234L,48235L,48236L,48237L,
8873148238L,48239L,48240L,48241L,48242L,48243L,48244L,48245L,48246L,48247L,
8873248248L,48249L,48250L,48251L,48252L,48253L,48254L,48255L,48256L,48257L,
8873348258L,48259L,48260L,48261L,48262L,48263L,48264L,48265L,48266L,48267L,
8873448268L,48269L,48270L,48271L,48272L,48273L,48274L,48275L,48276L,48277L,
8873548278L,48279L,48280L,48281L,48282L,48283L,48284L,48285L,48286L,48287L,
8873648288L,48289L,48290L,48291L,48292L,48293L,48294L,48295L,48296L,48297L,
8873748298L,48299L,48300L,48301L,48302L,48303L,48304L,48305L,48306L,48307L,
8873848308L,48309L,48310L,48311L,48312L,48313L,48314L,48315L,48316L,48317L,
8873948318L,48319L,48320L,48321L,48322L,48323L,48324L,48325L,48326L,48327L,
8874048328L,48329L,48330L,48331L,48332L,48333L,48334L,48335L,48336L,48337L,
8874148338L,48339L,48340L,48341L,48342L,48343L,48344L,48345L,48346L,48347L,
8874248348L,48349L,48350L,48351L,48352L,48353L,48354L,48355L,48356L,48357L,
8874348358L,48359L,48360L,48361L,48362L,48363L,48364L,48365L,48366L,48367L,
8874448368L,48369L,48370L,48371L,48372L,48373L,48374L,48375L,48376L,48377L,
8874548378L,48379L,48380L,48381L,48382L,48383L,48384L,48385L,48386L,48387L,
8874648388L,48389L,48390L,48391L,48392L,48393L,48394L,48395L,48396L,48397L,
8874748398L,48399L,48400L,48401L,48402L,48403L,48404L,48405L,48406L,48407L,
8874848408L,48409L,48410L,48411L,48412L,48413L,48414L,48415L,48416L,48417L,
8874948418L,48419L,48420L,48421L,48422L,48423L,48424L,48425L,48426L,48427L,
8875048428L,48429L,48430L,48431L,48432L,48433L,48434L,48435L,48436L,48437L,
8875148438L,48439L,48440L,48441L,48442L,48443L,48444L,48445L,48446L,48447L,
8875248448L,48449L,48450L,48451L,48452L,48453L,48454L,48455L,48456L,48457L,
8875348458L,48459L,48460L,48461L,48462L,48463L,48464L,48465L,48466L,48467L,
8875448468L,48469L,48470L,48471L,48472L,48473L,48474L,48475L,48476L,48477L,
8875548478L,48479L,48480L,48481L,48482L,48483L,48484L,48485L,48486L,48487L,
8875648488L,48489L,48490L,48491L,48492L,48493L,48494L,48495L,48496L,48497L,
8875748498L,48499L,48500L,48501L,48502L,48503L,48504L,48505L,48506L,48507L,
8875848508L,48509L,48510L,48511L,48512L,48513L,48514L,48515L,48516L,48517L,
8875948518L,48519L,48520L,48521L,48522L,48523L,48524L,48525L,48526L,48527L,
8876048528L,48529L,48530L,48531L,48532L,48533L,48534L,48535L,48536L,48537L,
8876148538L,48539L,48540L,48541L,48542L,48543L,48544L,48545L,48546L,48547L,
8876248548L,48549L,48550L,48551L,48552L,48553L,48554L,48555L,48556L,48557L,
8876348558L,48559L,48560L,48561L,48562L,48563L,48564L,48565L,48566L,48567L,
8876448568L,48569L,48570L,48571L,48572L,48573L,48574L,48575L,48576L,48577L,
8876548578L,48579L,48580L,48581L,48582L,48583L,48584L,48585L,48586L,48587L,
8876648588L,48589L,48590L,48591L,48592L,48593L,48594L,48595L,48596L,48597L,
8876748598L,48599L,48600L,48601L,48602L,48603L,48604L,48605L,48606L,48607L,
8876848608L,48609L,48610L,48611L,48612L,48613L,48614L,48615L,48616L,48617L,
8876948618L,48619L,48620L,48621L,48622L,48623L,48624L,48625L,48626L,48627L,
8877048628L,48629L,48630L,48631L,48632L,48633L,48634L,48635L,48636L,48637L,
8877148638L,48639L,48640L,48641L,48642L,48643L,48644L,48645L,48646L,48647L,
8877248648L,48649L,48650L,48651L,48652L,48653L,48654L,48655L,48656L,48657L,
8877348658L,48659L,48660L,48661L,48662L,48663L,48664L,48665L,48666L,48667L,
8877448668L,48669L,48670L,48671L,48672L,48673L,48674L,48675L,48676L,48677L,
8877548678L,48679L,48680L,48681L,48682L,48683L,48684L,48685L,48686L,48687L,
8877648688L,48689L,48690L,48691L,48692L,48693L,48694L,48695L,48696L,48697L,
8877748698L,48699L,48700L,48701L,48702L,48703L,48704L,48705L,48706L,48707L,
8877848708L,48709L,48710L,48711L,48712L,48713L,48714L,48715L,48716L,48717L,
8877948718L,48719L,48720L,48721L,48722L,48723L,48724L,48725L,48726L,48727L,
8878048728L,48729L,48730L,48731L,48732L,48733L,48734L,48735L,48736L,48737L,
8878148738L,48739L,48740L,48741L,48742L,48743L,48744L,48745L,48746L,48747L,
8878248748L,48749L,48750L,48751L,48752L,48753L,48754L,48755L,48756L,48757L,
8878348758L,48759L,48760L,48761L,48762L,48763L,48764L,48765L,48766L,48767L,
8878448768L,48769L,48770L,48771L,48772L,48773L,48774L,48775L,48776L,48777L,
8878548778L,48779L,48780L,48781L,48782L,48783L,48784L,48785L,48786L,48787L,
8878648788L,48789L,48790L,48791L,48792L,48793L,48794L,48795L,48796L,48797L,
8878748798L,48799L,48800L,48801L,48802L,48803L,48804L,48805L,48806L,48807L,
8878848808L,48809L,48810L,48811L,48812L,48813L,48814L,48815L,48816L,48817L,
8878948818L,48819L,48820L,48821L,48822L,48823L,48824L,48825L,48826L,48827L,
8879048828L,48829L,48830L,48831L,48832L,48833L,48834L,48835L,48836L,48837L,
8879148838L,48839L,48840L,48841L,48842L,48843L,48844L,48845L,48846L,48847L,
8879248848L,48849L,48850L,48851L,48852L,48853L,48854L,48855L,48856L,48857L,
8879348858L,48859L,48860L,48861L,48862L,48863L,48864L,48865L,48866L,48867L,
8879448868L,48869L,48870L,48871L,48872L,48873L,48874L,48875L,48876L,48877L,
8879548878L,48879L,48880L,48881L,48882L,48883L,48884L,48885L,48886L,48887L,
8879648888L,48889L,48890L,48891L,48892L,48893L,48894L,48895L,48896L,48897L,
8879748898L,48899L,48900L,48901L,48902L,48903L,48904L,48905L,48906L,48907L,
8879848908L,48909L,48910L,48911L,48912L,48913L,48914L,48915L,48916L,48917L,
8879948918L,48919L,48920L,48921L,48922L,48923L,48924L,48925L,48926L,48927L,
8880048928L,48929L,48930L,48931L,48932L,48933L,48934L,48935L,48936L,48937L,
8880148938L,48939L,48940L,48941L,48942L,48943L,48944L,48945L,48946L,48947L,
8880248948L,48949L,48950L,48951L,48952L,48953L,48954L,48955L,48956L,48957L,
8880348958L,48959L,48960L,48961L,48962L,48963L,48964L,48965L,48966L,48967L,
8880448968L,48969L,48970L,48971L,48972L,48973L,48974L,48975L,48976L,48977L,
8880548978L,48979L,48980L,48981L,48982L,48983L,48984L,48985L,48986L,48987L,
8880648988L,48989L,48990L,48991L,48992L,48993L,48994L,48995L,48996L,48997L,
8880748998L,48999L,49000L,49001L,49002L,49003L,49004L,49005L,49006L,49007L,
8880849008L,49009L,49010L,49011L,49012L,49013L,49014L,49015L,49016L,49017L,
8880949018L,49019L,49020L,49021L,49022L,49023L,49024L,49025L,49026L,49027L,
8881049028L,49029L,49030L,49031L,49032L,49033L,49034L,49035L,49036L,49037L,
8881149038L,49039L,49040L,49041L,49042L,49043L,49044L,49045L,49046L,49047L,
8881249048L,49049L,49050L,49051L,49052L,49053L,49054L,49055L,49056L,49057L,
8881349058L,49059L,49060L,49061L,49062L,49063L,49064L,49065L,49066L,49067L,
8881449068L,49069L,49070L,49071L,49072L,49073L,49074L,49075L,49076L,49077L,
8881549078L,49079L,49080L,49081L,49082L,49083L,49084L,49085L,49086L,49087L,
8881649088L,49089L,49090L,49091L,49092L,49093L,49094L,49095L,49096L,49097L,
8881749098L,49099L,49100L,49101L,49102L,49103L,49104L,49105L,49106L,49107L,
8881849108L,49109L,49110L,49111L,49112L,49113L,49114L,49115L,49116L,49117L,
8881949118L,49119L,49120L,49121L,49122L,49123L,49124L,49125L,49126L,49127L,
8882049128L,49129L,49130L,49131L,49132L,49133L,49134L,49135L,49136L,49137L,
8882149138L,49139L,49140L,49141L,49142L,49143L,49144L,49145L,49146L,49147L,
8882249148L,49149L,49150L,49151L,49152L,49153L,49154L,49155L,49156L,49157L,
8882349158L,49159L,49160L,49161L,49162L,49163L,49164L,49165L,49166L,49167L,
8882449168L,49169L,49170L,49171L,49172L,49173L,49174L,49175L,49176L,49177L,
8882549178L,49179L,49180L,49181L,49182L,49183L,49184L,49185L,49186L,49187L,
8882649188L,49189L,49190L,49191L,49192L,49193L,49194L,49195L,49196L,49197L,
8882749198L,49199L,49200L,49201L,49202L,49203L,49204L,49205L,49206L,49207L,
8882849208L,49209L,49210L,49211L,49212L,49213L,49214L,49215L,49216L,49217L,
8882949218L,49219L,49220L,49221L,49222L,49223L,49224L,49225L,49226L,49227L,
8883049228L,49229L,49230L,49231L,49232L,49233L,49234L,49235L,49236L,49237L,
8883149238L,49239L,49240L,49241L,49242L,49243L,49244L,49245L,49246L,49247L,
8883249248L,49249L,49250L,49251L,49252L,49253L,49254L,49255L,49256L,49257L,
8883349258L,49259L,49260L,49261L,49262L,49263L,49264L,49265L,49266L,49267L,
8883449268L,49269L,49270L,49271L,49272L,49273L,49274L,49275L,49276L,49277L,
8883549278L,49279L,49280L,49281L,49282L,49283L,49284L,49285L,49286L,49287L,
8883649288L,49289L,49290L,49291L,49292L,49293L,49294L,49295L,49296L,49297L,
8883749298L,49299L,49300L,49301L,49302L,49303L,49304L,49305L,49306L,49307L,
8883849308L,49309L,49310L,49311L,49312L,49313L,49314L,49315L,49316L,49317L,
8883949318L,49319L,49320L,49321L,49322L,49323L,49324L,49325L,49326L,49327L,
8884049328L,49329L,49330L,49331L,49332L,49333L,49334L,49335L,49336L,49337L,
8884149338L,49339L,49340L,49341L,49342L,49343L,49344L,49345L,49346L,49347L,
8884249348L,49349L,49350L,49351L,49352L,49353L,49354L,49355L,49356L,49357L,
8884349358L,49359L,49360L,49361L,49362L,49363L,49364L,49365L,49366L,49367L,
8884449368L,49369L,49370L,49371L,49372L,49373L,49374L,49375L,49376L,49377L,
8884549378L,49379L,49380L,49381L,49382L,49383L,49384L,49385L,49386L,49387L,
8884649388L,49389L,49390L,49391L,49392L,49393L,49394L,49395L,49396L,49397L,
8884749398L,49399L,49400L,49401L,49402L,49403L,49404L,49405L,49406L,49407L,
8884849408L,49409L,49410L,49411L,49412L,49413L,49414L,49415L,49416L,49417L,
8884949418L,49419L,49420L,49421L,49422L,49423L,49424L,49425L,49426L,49427L,
8885049428L,49429L,49430L,49431L,49432L,49433L,49434L,49435L,49436L,49437L,
8885149438L,49439L,49440L,49441L,49442L,49443L,49444L,49445L,49446L,49447L,
8885249448L,49449L,49450L,49451L,49452L,49453L,49454L,49455L,49456L,49457L,
8885349458L,49459L,49460L,49461L,49462L,49463L,49464L,49465L,49466L,49467L,
8885449468L,49469L,49470L,49471L,49472L,49473L,49474L,49475L,49476L,49477L,
8885549478L,49479L,49480L,49481L,49482L,49483L,49484L,49485L,49486L,49487L,
8885649488L,49489L,49490L,49491L,49492L,49493L,49494L,49495L,49496L,49497L,
8885749498L,49499L,49500L,49501L,49502L,49503L,49504L,49505L,49506L,49507L,
8885849508L,49509L,49510L,49511L,49512L,49513L,49514L,49515L,49516L,49517L,
8885949518L,49519L,49520L,49521L,49522L,49523L,49524L,49525L,49526L,49527L,
8886049528L,49529L,49530L,49531L,49532L,49533L,49534L,49535L,49536L,49537L,
8886149538L,49539L,49540L,49541L,49542L,49543L,49544L,49545L,49546L,49547L,
8886249548L,49549L,49550L,49551L,49552L,49553L,49554L,49555L,49556L,49557L,
8886349558L,49559L,49560L,49561L,49562L,49563L,49564L,49565L,49566L,49567L,
8886449568L,49569L,49570L,49571L,49572L,49573L,49574L,49575L,49576L,49577L,
8886549578L,49579L,49580L,49581L,49582L,49583L,49584L,49585L,49586L,49587L,
8886649588L,49589L,49590L,49591L,49592L,49593L,49594L,49595L,49596L,49597L,
8886749598L,49599L,49600L,49601L,49602L,49603L,49604L,49605L,49606L,49607L,
8886849608L,49609L,49610L,49611L,49612L,49613L,49614L,49615L,49616L,49617L,
8886949618L,49619L,49620L,49621L,49622L,49623L,49624L,49625L,49626L,49627L,
8887049628L,49629L,49630L,49631L,49632L,49633L,49634L,49635L,49636L,49637L,
8887149638L,49639L,49640L,49641L,49642L,49643L,49644L,49645L,49646L,49647L,
8887249648L,49649L,49650L,49651L,49652L,49653L,49654L,49655L,49656L,49657L,
8887349658L,49659L,49660L,49661L,49662L,49663L,49664L,49665L,49666L,49667L,
8887449668L,49669L,49670L,49671L,49672L,49673L,49674L,49675L,49676L,49677L,
8887549678L,49679L,49680L,49681L,49682L,49683L,49684L,49685L,49686L,49687L,
8887649688L,49689L,49690L,49691L,49692L,49693L,49694L,49695L,49696L,49697L,
8887749698L,49699L,49700L,49701L,49702L,49703L,49704L,49705L,49706L,49707L,
8887849708L,49709L,49710L,49711L,49712L,49713L,49714L,49715L,49716L,49717L,
8887949718L,49719L,49720L,49721L,49722L,49723L,49724L,49725L,49726L,49727L,
8888049728L,49729L,49730L,49731L,49732L,49733L,49734L,49735L,49736L,49737L,
8888149738L,49739L,49740L,49741L,49742L,49743L,49744L,49745L,49746L,49747L,
8888249748L,49749L,49750L,49751L,49752L,49753L,49754L,49755L,49756L,49757L,
8888349758L,49759L,49760L,49761L,49762L,49763L,49764L,49765L,49766L,49767L,
8888449768L,49769L,49770L,49771L,49772L,49773L,49774L,49775L,49776L,49777L,
8888549778L,49779L,49780L,49781L,49782L,49783L,49784L,49785L,49786L,49787L,
8888649788L,49789L,49790L,49791L,49792L,49793L,49794L,49795L,49796L,49797L,
8888749798L,49799L,49800L,49801L,49802L,49803L,49804L,49805L,49806L,49807L,
8888849808L,49809L,49810L,49811L,49812L,49813L,49814L,49815L,49816L,49817L,
8888949818L,49819L,49820L,49821L,49822L,49823L,49824L,49825L,49826L,49827L,
8889049828L,49829L,49830L,49831L,49832L,49833L,49834L,49835L,49836L,49837L,
8889149838L,49839L,49840L,49841L,49842L,49843L,49844L,49845L,49846L,49847L,
8889249848L,49849L,49850L,49851L,49852L,49853L,49854L,49855L,49856L,49857L,
8889349858L,49859L,49860L,49861L,49862L,49863L,49864L,49865L,49866L,49867L,
8889449868L,49869L,49870L,49871L,49872L,49873L,49874L,49875L,49876L,49877L,
8889549878L,49879L,49880L,49881L,49882L,49883L,49884L,49885L,49886L,49887L,
8889649888L,49889L,49890L,49891L,49892L,49893L,49894L,49895L,49896L,49897L,
8889749898L,49899L,49900L,49901L,49902L,49903L,49904L,49905L,49906L,49907L,
8889849908L,49909L,49910L,49911L,49912L,49913L,49914L,49915L,49916L,49917L,
8889949918L,49919L,49920L,49921L,49922L,49923L,49924L,49925L,49926L,49927L,
8890049928L,49929L,49930L,49931L,49932L,49933L,49934L,49935L,49936L,49937L,
8890149938L,49939L,49940L,49941L,49942L,49943L,49944L,49945L,49946L,49947L,
8890249948L,49949L,49950L,49951L,49952L,49953L,49954L,49955L,49956L,49957L,
8890349958L,49959L,49960L,49961L,49962L,49963L,49964L,49965L,49966L,49967L,
8890449968L,49969L,49970L,49971L,49972L,49973L,49974L,49975L,49976L,49977L,
8890549978L,49979L,49980L,49981L,49982L,49983L,49984L,49985L,49986L,49987L,
8890649988L,49989L,49990L,49991L,49992L,49993L,49994L,49995L,49996L,49997L,
8890749998L,49999L,50000L,50001L,50002L,50003L,50004L,50005L,50006L,50007L,
8890850008L,50009L,50010L,50011L,50012L,50013L,50014L,50015L,50016L,50017L,
8890950018L,50019L,50020L,50021L,50022L,50023L,50024L,50025L,50026L,50027L,
8891050028L,50029L,50030L,50031L,50032L,50033L,50034L,50035L,50036L,50037L,
8891150038L,50039L,50040L,50041L,50042L,50043L,50044L,50045L,50046L,50047L,
8891250048L,50049L,50050L,50051L,50052L,50053L,50054L,50055L,50056L,50057L,
8891350058L,50059L,50060L,50061L,50062L,50063L,50064L,50065L,50066L,50067L,
8891450068L,50069L,50070L,50071L,50072L,50073L,50074L,50075L,50076L,50077L,
8891550078L,50079L,50080L,50081L,50082L,50083L,50084L,50085L,50086L,50087L,
8891650088L,50089L,50090L,50091L,50092L,50093L,50094L,50095L,50096L,50097L,
8891750098L,50099L,50100L,50101L,50102L,50103L,50104L,50105L,50106L,50107L,
8891850108L,50109L,50110L,50111L,50112L,50113L,50114L,50115L,50116L,50117L,
8891950118L,50119L,50120L,50121L,50122L,50123L,50124L,50125L,50126L,50127L,
8892050128L,50129L,50130L,50131L,50132L,50133L,50134L,50135L,50136L,50137L,
8892150138L,50139L,50140L,50141L,50142L,50143L,50144L,50145L,50146L,50147L,
8892250148L,50149L,50150L,50151L,50152L,50153L,50154L,50155L,50156L,50157L,
8892350158L,50159L,50160L,50161L,50162L,50163L,50164L,50165L,50166L,50167L,
8892450168L,50169L,50170L,50171L,50172L,50173L,50174L,50175L,50176L,50177L,
8892550178L,50179L,50180L,50181L,50182L,50183L,50184L,50185L,50186L,50187L,
8892650188L,50189L,50190L,50191L,50192L,50193L,50194L,50195L,50196L,50197L,
8892750198L,50199L,50200L,50201L,50202L,50203L,50204L,50205L,50206L,50207L,
8892850208L,50209L,50210L,50211L,50212L,50213L,50214L,50215L,50216L,50217L,
8892950218L,50219L,50220L,50221L,50222L,50223L,50224L,50225L,50226L,50227L,
8893050228L,50229L,50230L,50231L,50232L,50233L,50234L,50235L,50236L,50237L,
8893150238L,50239L,50240L,50241L,50242L,50243L,50244L,50245L,50246L,50247L,
8893250248L,50249L,50250L,50251L,50252L,50253L,50254L,50255L,50256L,50257L,
8893350258L,50259L,50260L,50261L,50262L,50263L,50264L,50265L,50266L,50267L,
8893450268L,50269L,50270L,50271L,50272L,50273L,50274L,50275L,50276L,50277L,
8893550278L,50279L,50280L,50281L,50282L,50283L,50284L,50285L,50286L,50287L,
8893650288L,50289L,50290L,50291L,50292L,50293L,50294L,50295L,50296L,50297L,
8893750298L,50299L,50300L,50301L,50302L,50303L,50304L,50305L,50306L,50307L,
8893850308L,50309L,50310L,50311L,50312L,50313L,50314L,50315L,50316L,50317L,
8893950318L,50319L,50320L,50321L,50322L,50323L,50324L,50325L,50326L,50327L,
8894050328L,50329L,50330L,50331L,50332L,50333L,50334L,50335L,50336L,50337L,
8894150338L,50339L,50340L,50341L,50342L,50343L,50344L,50345L,50346L,50347L,
8894250348L,50349L,50350L,50351L,50352L,50353L,50354L,50355L,50356L,50357L,
8894350358L,50359L,50360L,50361L,50362L,50363L,50364L,50365L,50366L,50367L,
8894450368L,50369L,50370L,50371L,50372L,50373L,50374L,50375L,50376L,50377L,
8894550378L,50379L,50380L,50381L,50382L,50383L,50384L,50385L,50386L,50387L,
8894650388L,50389L,50390L,50391L,50392L,50393L,50394L,50395L,50396L,50397L,
8894750398L,50399L,50400L,50401L,50402L,50403L,50404L,50405L,50406L,50407L,
8894850408L,50409L,50410L,50411L,50412L,50413L,50414L,50415L,50416L,50417L,
8894950418L,50419L,50420L,50421L,50422L,50423L,50424L,50425L,50426L,50427L,
8895050428L,50429L,50430L,50431L,50432L,50433L,50434L,50435L,50436L,50437L,
8895150438L,50439L,50440L,50441L,50442L,50443L,50444L,50445L,50446L,50447L,
8895250448L,50449L,50450L,50451L,50452L,50453L,50454L,50455L,50456L,50457L,
8895350458L,50459L,50460L,50461L,50462L,50463L,50464L,50465L,50466L,50467L,
8895450468L,50469L,50470L,50471L,50472L,50473L,50474L,50475L,50476L,50477L,
8895550478L,50479L,50480L,50481L,50482L,50483L,50484L,50485L,50486L,50487L,
8895650488L,50489L,50490L,50491L,50492L,50493L,50494L,50495L,50496L,50497L,
8895750498L,50499L,50500L,50501L,50502L,50503L,50504L,50505L,50506L,50507L,
8895850508L,50509L,50510L,50511L,50512L,50513L,50514L,50515L,50516L,50517L,
8895950518L,50519L,50520L,50521L,50522L,50523L,50524L,50525L,50526L,50527L,
8896050528L,50529L,50530L,50531L,50532L,50533L,50534L,50535L,50536L,50537L,
8896150538L,50539L,50540L,50541L,50542L,50543L,50544L,50545L,50546L,50547L,
8896250548L,50549L,50550L,50551L,50552L,50553L,50554L,50555L,50556L,50557L,
8896350558L,50559L,50560L,50561L,50562L,50563L,50564L,50565L,50566L,50567L,
8896450568L,50569L,50570L,50571L,50572L,50573L,50574L,50575L,50576L,50577L,
8896550578L,50579L,50580L,50581L,50582L,50583L,50584L,50585L,50586L,50587L,
8896650588L,50589L,50590L,50591L,50592L,50593L,50594L,50595L,50596L,50597L,
8896750598L,50599L,50600L,50601L,50602L,50603L,50604L,50605L,50606L,50607L,
8896850608L,50609L,50610L,50611L,50612L,50613L,50614L,50615L,50616L,50617L,
8896950618L,50619L,50620L,50621L,50622L,50623L,50624L,50625L,50626L,50627L,
8897050628L,50629L,50630L,50631L,50632L,50633L,50634L,50635L,50636L,50637L,
8897150638L,50639L,50640L,50641L,50642L,50643L,50644L,50645L,50646L,50647L,
8897250648L,50649L,50650L,50651L,50652L,50653L,50654L,50655L,50656L,50657L,
8897350658L,50659L,50660L,50661L,50662L,50663L,50664L,50665L,50666L,50667L,
8897450668L,50669L,50670L,50671L,50672L,50673L,50674L,50675L,50676L,50677L,
8897550678L,50679L,50680L,50681L,50682L,50683L,50684L,50685L,50686L,50687L,
8897650688L,50689L,50690L,50691L,50692L,50693L,50694L,50695L,50696L,50697L,
8897750698L,50699L,50700L,50701L,50702L,50703L,50704L,50705L,50706L,50707L,
8897850708L,50709L,50710L,50711L,50712L,50713L,50714L,50715L,50716L,50717L,
8897950718L,50719L,50720L,50721L,50722L,50723L,50724L,50725L,50726L,50727L,
8898050728L,50729L,50730L,50731L,50732L,50733L,50734L,50735L,50736L,50737L,
8898150738L,50739L,50740L,50741L,50742L,50743L,50744L,50745L,50746L,50747L,
8898250748L,50749L,50750L,50751L,50752L,50753L,50754L,50755L,50756L,50757L,
8898350758L,50759L,50760L,50761L,50762L,50763L,50764L,50765L,50766L,50767L,
8898450768L,50769L,50770L,50771L,50772L,50773L,50774L,50775L,50776L,50777L,
8898550778L,50779L,50780L,50781L,50782L,50783L,50784L,50785L,50786L,50787L,
8898650788L,50789L,50790L,50791L,50792L,50793L,50794L,50795L,50796L,50797L,
8898750798L,50799L,50800L,50801L,50802L,50803L,50804L,50805L,50806L,50807L,
8898850808L,50809L,50810L,50811L,50812L,50813L,50814L,50815L,50816L,50817L,
8898950818L,50819L,50820L,50821L,50822L,50823L,50824L,50825L,50826L,50827L,
8899050828L,50829L,50830L,50831L,50832L,50833L,50834L,50835L,50836L,50837L,
8899150838L,50839L,50840L,50841L,50842L,50843L,50844L,50845L,50846L,50847L,
8899250848L,50849L,50850L,50851L,50852L,50853L,50854L,50855L,50856L,50857L,
8899350858L,50859L,50860L,50861L,50862L,50863L,50864L,50865L,50866L,50867L,
8899450868L,50869L,50870L,50871L,50872L,50873L,50874L,50875L,50876L,50877L,
8899550878L,50879L,50880L,50881L,50882L,50883L,50884L,50885L,50886L,50887L,
8899650888L,50889L,50890L,50891L,50892L,50893L,50894L,50895L,50896L,50897L,
8899750898L,50899L,50900L,50901L,50902L,50903L,50904L,50905L,50906L,50907L,
8899850908L,50909L,50910L,50911L,50912L,50913L,50914L,50915L,50916L,50917L,
8899950918L,50919L,50920L,50921L,50922L,50923L,50924L,50925L,50926L,50927L,
8900050928L,50929L,50930L,50931L,50932L,50933L,50934L,50935L,50936L,50937L,
8900150938L,50939L,50940L,50941L,50942L,50943L,50944L,50945L,50946L,50947L,
8900250948L,50949L,50950L,50951L,50952L,50953L,50954L,50955L,50956L,50957L,
8900350958L,50959L,50960L,50961L,50962L,50963L,50964L,50965L,50966L,50967L,
8900450968L,50969L,50970L,50971L,50972L,50973L,50974L,50975L,50976L,50977L,
8900550978L,50979L,50980L,50981L,50982L,50983L,50984L,50985L,50986L,50987L,
8900650988L,50989L,50990L,50991L,50992L,50993L,50994L,50995L,50996L,50997L,
8900750998L,50999L,51000L,51001L,51002L,51003L,51004L,51005L,51006L,51007L,
8900851008L,51009L,51010L,51011L,51012L,51013L,51014L,51015L,51016L,51017L,
8900951018L,51019L,51020L,51021L,51022L,51023L,51024L,51025L,51026L,51027L,
8901051028L,51029L,51030L,51031L,51032L,51033L,51034L,51035L,51036L,51037L,
8901151038L,51039L,51040L,51041L,51042L,51043L,51044L,51045L,51046L,51047L,
8901251048L,51049L,51050L,51051L,51052L,51053L,51054L,51055L,51056L,51057L,
8901351058L,51059L,51060L,51061L,51062L,51063L,51064L,51065L,51066L,51067L,
8901451068L,51069L,51070L,51071L,51072L,51073L,51074L,51075L,51076L,51077L,
8901551078L,51079L,51080L,51081L,51082L,51083L,51084L,51085L,51086L,51087L,
8901651088L,51089L,51090L,51091L,51092L,51093L,51094L,51095L,51096L,51097L,
8901751098L,51099L,51100L,51101L,51102L,51103L,51104L,51105L,51106L,51107L,
8901851108L,51109L,51110L,51111L,51112L,51113L,51114L,51115L,51116L,51117L,
8901951118L,51119L,51120L,51121L,51122L,51123L,51124L,51125L,51126L,51127L,
8902051128L,51129L,51130L,51131L,51132L,51133L,51134L,51135L,51136L,51137L,
8902151138L,51139L,51140L,51141L,51142L,51143L,51144L,51145L,51146L,51147L,
8902251148L,51149L,51150L,51151L,51152L,51153L,51154L,51155L,51156L,51157L,
8902351158L,51159L,51160L,51161L,51162L,51163L,51164L,51165L,51166L,51167L,
8902451168L,51169L,51170L,51171L,51172L,51173L,51174L,51175L,51176L,51177L,
8902551178L,51179L,51180L,51181L,51182L,51183L,51184L,51185L,51186L,51187L,
8902651188L,51189L,51190L,51191L,51192L,51193L,51194L,51195L,51196L,51197L,
8902751198L,51199L,51200L,51201L,51202L,51203L,51204L,51205L,51206L,51207L,
8902851208L,51209L,51210L,51211L,51212L,51213L,51214L,51215L,51216L,51217L,
8902951218L,51219L,51220L,51221L,51222L,51223L,51224L,51225L,51226L,51227L,
8903051228L,51229L,51230L,51231L,51232L,51233L,51234L,51235L,51236L,51237L,
8903151238L,51239L,51240L,51241L,51242L,51243L,51244L,51245L,51246L,51247L,
8903251248L,51249L,51250L,51251L,51252L,51253L,51254L,51255L,51256L,51257L,
8903351258L,51259L,51260L,51261L,51262L,51263L,51264L,51265L,51266L,51267L,
8903451268L,51269L,51270L,51271L,51272L,51273L,51274L,51275L,51276L,51277L,
8903551278L,51279L,51280L,51281L,51282L,51283L,51284L,51285L,51286L,51287L,
8903651288L,51289L,51290L,51291L,51292L,51293L,51294L,51295L,51296L,51297L,
8903751298L,51299L,51300L,51301L,51302L,51303L,51304L,51305L,51306L,51307L,
8903851308L,51309L,51310L,51311L,51312L,51313L,51314L,51315L,51316L,51317L,
8903951318L,51319L,51320L,51321L,51322L,51323L,51324L,51325L,51326L,51327L,
8904051328L,51329L,51330L,51331L,51332L,51333L,51334L,51335L,51336L,51337L,
8904151338L,51339L,51340L,51341L,51342L,51343L,51344L,51345L,51346L,51347L,
8904251348L,51349L,51350L,51351L,51352L,51353L,51354L,51355L,51356L,51357L,
8904351358L,51359L,51360L,51361L,51362L,51363L,51364L,51365L,51366L,51367L,
8904451368L,51369L,51370L,51371L,51372L,51373L,51374L,51375L,51376L,51377L,
8904551378L,51379L,51380L,51381L,51382L,51383L,51384L,51385L,51386L,51387L,
8904651388L,51389L,51390L,51391L,51392L,51393L,51394L,51395L,51396L,51397L,
8904751398L,51399L,51400L,51401L,51402L,51403L,51404L,51405L,51406L,51407L,
8904851408L,51409L,51410L,51411L,51412L,51413L,51414L,51415L,51416L,51417L,
8904951418L,51419L,51420L,51421L,51422L,51423L,51424L,51425L,51426L,51427L,
8905051428L,51429L,51430L,51431L,51432L,51433L,51434L,51435L,51436L,51437L,
8905151438L,51439L,51440L,51441L,51442L,51443L,51444L,51445L,51446L,51447L,
8905251448L,51449L,51450L,51451L,51452L,51453L,51454L,51455L,51456L,51457L,
8905351458L,51459L,51460L,51461L,51462L,51463L,51464L,51465L,51466L,51467L,
8905451468L,51469L,51470L,51471L,51472L,51473L,51474L,51475L,51476L,51477L,
8905551478L,51479L,51480L,51481L,51482L,51483L,51484L,51485L,51486L,51487L,
8905651488L,51489L,51490L,51491L,51492L,51493L,51494L,51495L,51496L,51497L,
8905751498L,51499L,51500L,51501L,51502L,51503L,51504L,51505L,51506L,51507L,
8905851508L,51509L,51510L,51511L,51512L,51513L,51514L,51515L,51516L,51517L,
8905951518L,51519L,51520L,51521L,51522L,51523L,51524L,51525L,51526L,51527L,
8906051528L,51529L,51530L,51531L,51532L,51533L,51534L,51535L,51536L,51537L,
8906151538L,51539L,51540L,51541L,51542L,51543L,51544L,51545L,51546L,51547L,
8906251548L,51549L,51550L,51551L,51552L,51553L,51554L,51555L,51556L,51557L,
8906351558L,51559L,51560L,51561L,51562L,51563L,51564L,51565L,51566L,51567L,
8906451568L,51569L,51570L,51571L,51572L,51573L,51574L,51575L,51576L,51577L,
8906551578L,51579L,51580L,51581L,51582L,51583L,51584L,51585L,51586L,51587L,
8906651588L,51589L,51590L,51591L,51592L,51593L,51594L,51595L,51596L,51597L,
8906751598L,51599L,51600L,51601L,51602L,51603L,51604L,51605L,51606L,51607L,
8906851608L,51609L,51610L,51611L,51612L,51613L,51614L,51615L,51616L,51617L,
8906951618L,51619L,51620L,51621L,51622L,51623L,51624L,51625L,51626L,51627L,
8907051628L,51629L,51630L,51631L,51632L,51633L,51634L,51635L,51636L,51637L,
8907151638L,51639L,51640L,51641L,51642L,51643L,51644L,51645L,51646L,51647L,
8907251648L,51649L,51650L,51651L,51652L,51653L,51654L,51655L,51656L,51657L,
8907351658L,51659L,51660L,51661L,51662L,51663L,51664L,51665L,51666L,51667L,
8907451668L,51669L,51670L,51671L,51672L,51673L,51674L,51675L,51676L,51677L,
8907551678L,51679L,51680L,51681L,51682L,51683L,51684L,51685L,51686L,51687L,
8907651688L,51689L,51690L,51691L,51692L,51693L,51694L,51695L,51696L,51697L,
8907751698L,51699L,51700L,51701L,51702L,51703L,51704L,51705L,51706L,51707L,
8907851708L,51709L,51710L,51711L,51712L,51713L,51714L,51715L,51716L,51717L,
8907951718L,51719L,51720L,51721L,51722L,51723L,51724L,51725L,51726L,51727L,
8908051728L,51729L,51730L,51731L,51732L,51733L,51734L,51735L,51736L,51737L,
8908151738L,51739L,51740L,51741L,51742L,51743L,51744L,51745L,51746L,51747L,
8908251748L,51749L,51750L,51751L,51752L,51753L,51754L,51755L,51756L,51757L,
8908351758L,51759L,51760L,51761L,51762L,51763L,51764L,51765L,51766L,51767L,
8908451768L,51769L,51770L,51771L,51772L,51773L,51774L,51775L,51776L,51777L,
8908551778L,51779L,51780L,51781L,51782L,51783L,51784L,51785L,51786L,51787L,
8908651788L,51789L,51790L,51791L,51792L,51793L,51794L,51795L,51796L,51797L,
8908751798L,51799L,51800L,51801L,51802L,51803L,51804L,51805L,51806L,51807L,
8908851808L,51809L,51810L,51811L,51812L,51813L,51814L,51815L,51816L,51817L,
8908951818L,51819L,51820L,51821L,51822L,51823L,51824L,51825L,51826L,51827L,
8909051828L,51829L,51830L,51831L,51832L,51833L,51834L,51835L,51836L,51837L,
8909151838L,51839L,51840L,51841L,51842L,51843L,51844L,51845L,51846L,51847L,
8909251848L,51849L,51850L,51851L,51852L,51853L,51854L,51855L,51856L,51857L,
8909351858L,51859L,51860L,51861L,51862L,51863L,51864L,51865L,51866L,51867L,
8909451868L,51869L,51870L,51871L,51872L,51873L,51874L,51875L,51876L,51877L,
8909551878L,51879L,51880L,51881L,51882L,51883L,51884L,51885L,51886L,51887L,
8909651888L,51889L,51890L,51891L,51892L,51893L,51894L,51895L,51896L,51897L,
8909751898L,51899L,51900L,51901L,51902L,51903L,51904L,51905L,51906L,51907L,
8909851908L,51909L,51910L,51911L,51912L,51913L,51914L,51915L,51916L,51917L,
8909951918L,51919L,51920L,51921L,51922L,51923L,51924L,51925L,51926L,51927L,
8910051928L,51929L,51930L,51931L,51932L,51933L,51934L,51935L,51936L,51937L,
8910151938L,51939L,51940L,51941L,51942L,51943L,51944L,51945L,51946L,51947L,
8910251948L,51949L,51950L,51951L,51952L,51953L,51954L,51955L,51956L,51957L,
8910351958L,51959L,51960L,51961L,51962L,51963L,51964L,51965L,51966L,51967L,
8910451968L,51969L,51970L,51971L,51972L,51973L,51974L,51975L,51976L,51977L,
8910551978L,51979L,51980L,51981L,51982L,51983L,51984L,51985L,51986L,51987L,
8910651988L,51989L,51990L,51991L,51992L,51993L,51994L,51995L,51996L,51997L,
8910751998L,51999L,52000L,52001L,52002L,52003L,52004L,52005L,52006L,52007L,
8910852008L,52009L,52010L,52011L,52012L,52013L,52014L,52015L,52016L,52017L,
8910952018L,52019L,52020L,52021L,52022L,52023L,52024L,52025L,52026L,52027L,
8911052028L,52029L,52030L,52031L,52032L,52033L,52034L,52035L,52036L,52037L,
8911152038L,52039L,52040L,52041L,52042L,52043L,52044L,52045L,52046L,52047L,
8911252048L,52049L,52050L,52051L,52052L,52053L,52054L,52055L,52056L,52057L,
8911352058L,52059L,52060L,52061L,52062L,52063L,52064L,52065L,52066L,52067L,
8911452068L,52069L,52070L,52071L,52072L,52073L,52074L,52075L,52076L,52077L,
8911552078L,52079L,52080L,52081L,52082L,52083L,52084L,52085L,52086L,52087L,
8911652088L,52089L,52090L,52091L,52092L,52093L,52094L,52095L,52096L,52097L,
8911752098L,52099L,52100L,52101L,52102L,52103L,52104L,52105L,52106L,52107L,
8911852108L,52109L,52110L,52111L,52112L,52113L,52114L,52115L,52116L,52117L,
8911952118L,52119L,52120L,52121L,52122L,52123L,52124L,52125L,52126L,52127L,
8912052128L,52129L,52130L,52131L,52132L,52133L,52134L,52135L,52136L,52137L,
8912152138L,52139L,52140L,52141L,52142L,52143L,52144L,52145L,52146L,52147L,
8912252148L,52149L,52150L,52151L,52152L,52153L,52154L,52155L,52156L,52157L,
8912352158L,52159L,52160L,52161L,52162L,52163L,52164L,52165L,52166L,52167L,
8912452168L,52169L,52170L,52171L,52172L,52173L,52174L,52175L,52176L,52177L,
8912552178L,52179L,52180L,52181L,52182L,52183L,52184L,52185L,52186L,52187L,
8912652188L,52189L,52190L,52191L,52192L,52193L,52194L,52195L,52196L,52197L,
8912752198L,52199L,52200L,52201L,52202L,52203L,52204L,52205L,52206L,52207L,
8912852208L,52209L,52210L,52211L,52212L,52213L,52214L,52215L,52216L,52217L,
8912952218L,52219L,52220L,52221L,52222L,52223L,52224L,52225L,52226L,52227L,
8913052228L,52229L,52230L,52231L,52232L,52233L,52234L,52235L,52236L,52237L,
8913152238L,52239L,52240L,52241L,52242L,52243L,52244L,52245L,52246L,52247L,
8913252248L,52249L,52250L,52251L,52252L,52253L,52254L,52255L,52256L,52257L,
8913352258L,52259L,52260L,52261L,52262L,52263L,52264L,52265L,52266L,52267L,
8913452268L,52269L,52270L,52271L,52272L,52273L,52274L,52275L,52276L,52277L,
8913552278L,52279L,52280L,52281L,52282L,52283L,52284L,52285L,52286L,52287L,
8913652288L,52289L,52290L,52291L,52292L,52293L,52294L,52295L,52296L,52297L,
8913752298L,52299L,52300L,52301L,52302L,52303L,52304L,52305L,52306L,52307L,
8913852308L,52309L,52310L,52311L,52312L,52313L,52314L,52315L,52316L,52317L,
8913952318L,52319L,52320L,52321L,52322L,52323L,52324L,52325L,52326L,52327L,
8914052328L,52329L,52330L,52331L,52332L,52333L,52334L,52335L,52336L,52337L,
8914152338L,52339L,52340L,52341L,52342L,52343L,52344L,52345L,52346L,52347L,
8914252348L,52349L,52350L,52351L,52352L,52353L,52354L,52355L,52356L,52357L,
8914352358L,52359L,52360L,52361L,52362L,52363L,52364L,52365L,52366L,52367L,
8914452368L,52369L,52370L,52371L,52372L,52373L,52374L,52375L,52376L,52377L,
8914552378L,52379L,52380L,52381L,52382L,52383L,52384L,52385L,52386L,52387L,
8914652388L,52389L,52390L,52391L,52392L,52393L,52394L,52395L,52396L,52397L,
8914752398L,52399L,52400L,52401L,52402L,52403L,52404L,52405L,52406L,52407L,
8914852408L,52409L,52410L,52411L,52412L,52413L,52414L,52415L,52416L,52417L,
8914952418L,52419L,52420L,52421L,52422L,52423L,52424L,52425L,52426L,52427L,
8915052428L,52429L,52430L,52431L,52432L,52433L,52434L,52435L,52436L,52437L,
8915152438L,52439L,52440L,52441L,52442L,52443L,52444L,52445L,52446L,52447L,
8915252448L,52449L,52450L,52451L,52452L,52453L,52454L,52455L,52456L,52457L,
8915352458L,52459L,52460L,52461L,52462L,52463L,52464L,52465L,52466L,52467L,
8915452468L,52469L,52470L,52471L,52472L,52473L,52474L,52475L,52476L,52477L,
8915552478L,52479L,52480L,52481L,52482L,52483L,52484L,52485L,52486L,52487L,
8915652488L,52489L,52490L,52491L,52492L,52493L,52494L,52495L,52496L,52497L,
8915752498L,52499L,52500L,52501L,52502L,52503L,52504L,52505L,52506L,52507L,
8915852508L,52509L,52510L,52511L,52512L,52513L,52514L,52515L,52516L,52517L,
8915952518L,52519L,52520L,52521L,52522L,52523L,52524L,52525L,52526L,52527L,
8916052528L,52529L,52530L,52531L,52532L,52533L,52534L,52535L,52536L,52537L,
8916152538L,52539L,52540L,52541L,52542L,52543L,52544L,52545L,52546L,52547L,
8916252548L,52549L,52550L,52551L,52552L,52553L,52554L,52555L,52556L,52557L,
8916352558L,52559L,52560L,52561L,52562L,52563L,52564L,52565L,52566L,52567L,
8916452568L,52569L,52570L,52571L,52572L,52573L,52574L,52575L,52576L,52577L,
8916552578L,52579L,52580L,52581L,52582L,52583L,52584L,52585L,52586L,52587L,
8916652588L,52589L,52590L,52591L,52592L,52593L,52594L,52595L,52596L,52597L,
8916752598L,52599L,52600L,52601L,52602L,52603L,52604L,52605L,52606L,52607L,
8916852608L,52609L,52610L,52611L,52612L,52613L,52614L,52615L,52616L,52617L,
8916952618L,52619L,52620L,52621L,52622L,52623L,52624L,52625L,52626L,52627L,
8917052628L,52629L,52630L,52631L,52632L,52633L,52634L,52635L,52636L,52637L,
8917152638L,52639L,52640L,52641L,52642L,52643L,52644L,52645L,52646L,52647L,
8917252648L,52649L,52650L,52651L,52652L,52653L,52654L,52655L,52656L,52657L,
8917352658L,52659L,52660L,52661L,52662L,52663L,52664L,52665L,52666L,52667L,
8917452668L,52669L,52670L,52671L,52672L,52673L,52674L,52675L,52676L,52677L,
8917552678L,52679L,52680L,52681L,52682L,52683L,52684L,52685L,52686L,52687L,
8917652688L,52689L,52690L,52691L,52692L,52693L,52694L,52695L,52696L,52697L,
8917752698L,52699L,52700L,52701L,52702L,52703L,52704L,52705L,52706L,52707L,
8917852708L,52709L,52710L,52711L,52712L,52713L,52714L,52715L,52716L,52717L,
8917952718L,52719L,52720L,52721L,52722L,52723L,52724L,52725L,52726L,52727L,
8918052728L,52729L,52730L,52731L,52732L,52733L,52734L,52735L,52736L,52737L,
8918152738L,52739L,52740L,52741L,52742L,52743L,52744L,52745L,52746L,52747L,
8918252748L,52749L,52750L,52751L,52752L,52753L,52754L,52755L,52756L,52757L,
8918352758L,52759L,52760L,52761L,52762L,52763L,52764L,52765L,52766L,52767L,
8918452768L,52769L,52770L,52771L,52772L,52773L,52774L,52775L,52776L,52777L,
8918552778L,52779L,52780L,52781L,52782L,52783L,52784L,52785L,52786L,52787L,
8918652788L,52789L,52790L,52791L,52792L,52793L,52794L,52795L,52796L,52797L,
8918752798L,52799L,52800L,52801L,52802L,52803L,52804L,52805L,52806L,52807L,
8918852808L,52809L,52810L,52811L,52812L,52813L,52814L,52815L,52816L,52817L,
8918952818L,52819L,52820L,52821L,52822L,52823L,52824L,52825L,52826L,52827L,
8919052828L,52829L,52830L,52831L,52832L,52833L,52834L,52835L,52836L,52837L,
8919152838L,52839L,52840L,52841L,52842L,52843L,52844L,52845L,52846L,52847L,
8919252848L,52849L,52850L,52851L,52852L,52853L,52854L,52855L,52856L,52857L,
8919352858L,52859L,52860L,52861L,52862L,52863L,52864L,52865L,52866L,52867L,
8919452868L,52869L,52870L,52871L,52872L,52873L,52874L,52875L,52876L,52877L,
8919552878L,52879L,52880L,52881L,52882L,52883L,52884L,52885L,52886L,52887L,
8919652888L,52889L,52890L,52891L,52892L,52893L,52894L,52895L,52896L,52897L,
8919752898L,52899L,52900L,52901L,52902L,52903L,52904L,52905L,52906L,52907L,
8919852908L,52909L,52910L,52911L,52912L,52913L,52914L,52915L,52916L,52917L,
8919952918L,52919L,52920L,52921L,52922L,52923L,52924L,52925L,52926L,52927L,
8920052928L,52929L,52930L,52931L,52932L,52933L,52934L,52935L,52936L,52937L,
8920152938L,52939L,52940L,52941L,52942L,52943L,52944L,52945L,52946L,52947L,
8920252948L,52949L,52950L,52951L,52952L,52953L,52954L,52955L,52956L,52957L,
8920352958L,52959L,52960L,52961L,52962L,52963L,52964L,52965L,52966L,52967L,
8920452968L,52969L,52970L,52971L,52972L,52973L,52974L,52975L,52976L,52977L,
8920552978L,52979L,52980L,52981L,52982L,52983L,52984L,52985L,52986L,52987L,
8920652988L,52989L,52990L,52991L,52992L,52993L,52994L,52995L,52996L,52997L,
8920752998L,52999L,53000L,53001L,53002L,53003L,53004L,53005L,53006L,53007L,
8920853008L,53009L,53010L,53011L,53012L,53013L,53014L,53015L,53016L,53017L,
8920953018L,53019L,53020L,53021L,53022L,53023L,53024L,53025L,53026L,53027L,
8921053028L,53029L,53030L,53031L,53032L,53033L,53034L,53035L,53036L,53037L,
8921153038L,53039L,53040L,53041L,53042L,53043L,53044L,53045L,53046L,53047L,
8921253048L,53049L,53050L,53051L,53052L,53053L,53054L,53055L,53056L,53057L,
8921353058L,53059L,53060L,53061L,53062L,53063L,53064L,53065L,53066L,53067L,
8921453068L,53069L,53070L,53071L,53072L,53073L,53074L,53075L,53076L,53077L,
8921553078L,53079L,53080L,53081L,53082L,53083L,53084L,53085L,53086L,53087L,
8921653088L,53089L,53090L,53091L,53092L,53093L,53094L,53095L,53096L,53097L,
8921753098L,53099L,53100L,53101L,53102L,53103L,53104L,53105L,53106L,53107L,
8921853108L,53109L,53110L,53111L,53112L,53113L,53114L,53115L,53116L,53117L,
8921953118L,53119L,53120L,53121L,53122L,53123L,53124L,53125L,53126L,53127L,
8922053128L,53129L,53130L,53131L,53132L,53133L,53134L,53135L,53136L,53137L,
8922153138L,53139L,53140L,53141L,53142L,53143L,53144L,53145L,53146L,53147L,
8922253148L,53149L,53150L,53151L,53152L,53153L,53154L,53155L,53156L,53157L,
8922353158L,53159L,53160L,53161L,53162L,53163L,53164L,53165L,53166L,53167L,
8922453168L,53169L,53170L,53171L,53172L,53173L,53174L,53175L,53176L,53177L,
8922553178L,53179L,53180L,53181L,53182L,53183L,53184L,53185L,53186L,53187L,
8922653188L,53189L,53190L,53191L,53192L,53193L,53194L,53195L,53196L,53197L,
8922753198L,53199L,53200L,53201L,53202L,53203L,53204L,53205L,53206L,53207L,
8922853208L,53209L,53210L,53211L,53212L,53213L,53214L,53215L,53216L,53217L,
8922953218L,53219L,53220L,53221L,53222L,53223L,53224L,53225L,53226L,53227L,
8923053228L,53229L,53230L,53231L,53232L,53233L,53234L,53235L,53236L,53237L,
8923153238L,53239L,53240L,53241L,53242L,53243L,53244L,53245L,53246L,53247L,
8923253248L,53249L,53250L,53251L,53252L,53253L,53254L,53255L,53256L,53257L,
8923353258L,53259L,53260L,53261L,53262L,53263L,53264L,53265L,53266L,53267L,
8923453268L,53269L,53270L,53271L,53272L,53273L,53274L,53275L,53276L,53277L,
8923553278L,53279L,53280L,53281L,53282L,53283L,53284L,53285L,53286L,53287L,
8923653288L,53289L,53290L,53291L,53292L,53293L,53294L,53295L,53296L,53297L,
8923753298L,53299L,53300L,53301L,53302L,53303L,53304L,53305L,53306L,53307L,
8923853308L,53309L,53310L,53311L,53312L,53313L,53314L,53315L,53316L,53317L,
8923953318L,53319L,53320L,53321L,53322L,53323L,53324L,53325L,53326L,53327L,
8924053328L,53329L,53330L,53331L,53332L,53333L,53334L,53335L,53336L,53337L,
8924153338L,53339L,53340L,53341L,53342L,53343L,53344L,53345L,53346L,53347L,
8924253348L,53349L,53350L,53351L,53352L,53353L,53354L,53355L,53356L,53357L,
8924353358L,53359L,53360L,53361L,53362L,53363L,53364L,53365L,53366L,53367L,
8924453368L,53369L,53370L,53371L,53372L,53373L,53374L,53375L,53376L,53377L,
8924553378L,53379L,53380L,53381L,53382L,53383L,53384L,53385L,53386L,53387L,
8924653388L,53389L,53390L,53391L,53392L,53393L,53394L,53395L,53396L,53397L,
8924753398L,53399L,53400L,53401L,53402L,53403L,53404L,53405L,53406L,53407L,
8924853408L,53409L,53410L,53411L,53412L,53413L,53414L,53415L,53416L,53417L,
8924953418L,53419L,53420L,53421L,53422L,53423L,53424L,53425L,53426L,53427L,
8925053428L,53429L,53430L,53431L,53432L,53433L,53434L,53435L,53436L,53437L,
8925153438L,53439L,53440L,53441L,53442L,53443L,53444L,53445L,53446L,53447L,
8925253448L,53449L,53450L,53451L,53452L,53453L,53454L,53455L,53456L,53457L,
8925353458L,53459L,53460L,53461L,53462L,53463L,53464L,53465L,53466L,53467L,
8925453468L,53469L,53470L,53471L,53472L,53473L,53474L,53475L,53476L,53477L,
8925553478L,53479L,53480L,53481L,53482L,53483L,53484L,53485L,53486L,53487L,
8925653488L,53489L,53490L,53491L,53492L,53493L,53494L,53495L,53496L,53497L,
8925753498L,53499L,53500L,53501L,53502L,53503L,53504L,53505L,53506L,53507L,
8925853508L,53509L,53510L,53511L,53512L,53513L,53514L,53515L,53516L,53517L,
8925953518L,53519L,53520L,53521L,53522L,53523L,53524L,53525L,53526L,53527L,
8926053528L,53529L,53530L,53531L,53532L,53533L,53534L,53535L,53536L,53537L,
8926153538L,53539L,53540L,53541L,53542L,53543L,53544L,53545L,53546L,53547L,
8926253548L,53549L,53550L,53551L,53552L,53553L,53554L,53555L,53556L,53557L,
8926353558L,53559L,53560L,53561L,53562L,53563L,53564L,53565L,53566L,53567L,
8926453568L,53569L,53570L,53571L,53572L,53573L,53574L,53575L,53576L,53577L,
8926553578L,53579L,53580L,53581L,53582L,53583L,53584L,53585L,53586L,53587L,
8926653588L,53589L,53590L,53591L,53592L,53593L,53594L,53595L,53596L,53597L,
8926753598L,53599L,53600L,53601L,53602L,53603L,53604L,53605L,53606L,53607L,
8926853608L,53609L,53610L,53611L,53612L,53613L,53614L,53615L,53616L,53617L,
8926953618L,53619L,53620L,53621L,53622L,53623L,53624L,53625L,53626L,53627L,
8927053628L,53629L,53630L,53631L,53632L,53633L,53634L,53635L,53636L,53637L,
8927153638L,53639L,53640L,53641L,53642L,53643L,53644L,53645L,53646L,53647L,
8927253648L,53649L,53650L,53651L,53652L,53653L,53654L,53655L,53656L,53657L,
8927353658L,53659L,53660L,53661L,53662L,53663L,53664L,53665L,53666L,53667L,
8927453668L,53669L,53670L,53671L,53672L,53673L,53674L,53675L,53676L,53677L,
8927553678L,53679L,53680L,53681L,53682L,53683L,53684L,53685L,53686L,53687L,
8927653688L,53689L,53690L,53691L,53692L,53693L,53694L,53695L,53696L,53697L,
8927753698L,53699L,53700L,53701L,53702L,53703L,53704L,53705L,53706L,53707L,
8927853708L,53709L,53710L,53711L,53712L,53713L,53714L,53715L,53716L,53717L,
8927953718L,53719L,53720L,53721L,53722L,53723L,53724L,53725L,53726L,53727L,
8928053728L,53729L,53730L,53731L,53732L,53733L,53734L,53735L,53736L,53737L,
8928153738L,53739L,53740L,53741L,53742L,53743L,53744L,53745L,53746L,53747L,
8928253748L,53749L,53750L,53751L,53752L,53753L,53754L,53755L,53756L,53757L,
8928353758L,53759L,53760L,53761L,53762L,53763L,53764L,53765L,53766L,53767L,
8928453768L,53769L,53770L,53771L,53772L,53773L,53774L,53775L,53776L,53777L,
8928553778L,53779L,53780L,53781L,53782L,53783L,53784L,53785L,53786L,53787L,
8928653788L,53789L,53790L,53791L,53792L,53793L,53794L,53795L,53796L,53797L,
8928753798L,53799L,53800L,53801L,53802L,53803L,53804L,53805L,53806L,53807L,
8928853808L,53809L,53810L,53811L,53812L,53813L,53814L,53815L,53816L,53817L,
8928953818L,53819L,53820L,53821L,53822L,53823L,53824L,53825L,53826L,53827L,
8929053828L,53829L,53830L,53831L,53832L,53833L,53834L,53835L,53836L,53837L,
8929153838L,53839L,53840L,53841L,53842L,53843L,53844L,53845L,53846L,53847L,
8929253848L,53849L,53850L,53851L,53852L,53853L,53854L,53855L,53856L,53857L,
8929353858L,53859L,53860L,53861L,53862L,53863L,53864L,53865L,53866L,53867L,
8929453868L,53869L,53870L,53871L,53872L,53873L,53874L,53875L,53876L,53877L,
8929553878L,53879L,53880L,53881L,53882L,53883L,53884L,53885L,53886L,53887L,
8929653888L,53889L,53890L,53891L,53892L,53893L,53894L,53895L,53896L,53897L,
8929753898L,53899L,53900L,53901L,53902L,53903L,53904L,53905L,53906L,53907L,
8929853908L,53909L,53910L,53911L,53912L,53913L,53914L,53915L,53916L,53917L,
8929953918L,53919L,53920L,53921L,53922L,53923L,53924L,53925L,53926L,53927L,
8930053928L,53929L,53930L,53931L,53932L,53933L,53934L,53935L,53936L,53937L,
8930153938L,53939L,53940L,53941L,53942L,53943L,53944L,53945L,53946L,53947L,
8930253948L,53949L,53950L,53951L,53952L,53953L,53954L,53955L,53956L,53957L,
8930353958L,53959L,53960L,53961L,53962L,53963L,53964L,53965L,53966L,53967L,
8930453968L,53969L,53970L,53971L,53972L,53973L,53974L,53975L,53976L,53977L,
8930553978L,53979L,53980L,53981L,53982L,53983L,53984L,53985L,53986L,53987L,
8930653988L,53989L,53990L,53991L,53992L,53993L,53994L,53995L,53996L,53997L,
8930753998L,53999L,54000L,54001L,54002L,54003L,54004L,54005L,54006L,54007L,
8930854008L,54009L,54010L,54011L,54012L,54013L,54014L,54015L,54016L,54017L,
8930954018L,54019L,54020L,54021L,54022L,54023L,54024L,54025L,54026L,54027L,
8931054028L,54029L,54030L,54031L,54032L,54033L,54034L,54035L,54036L,54037L,
8931154038L,54039L,54040L,54041L,54042L,54043L,54044L,54045L,54046L,54047L,
8931254048L,54049L,54050L,54051L,54052L,54053L,54054L,54055L,54056L,54057L,
8931354058L,54059L,54060L,54061L,54062L,54063L,54064L,54065L,54066L,54067L,
8931454068L,54069L,54070L,54071L,54072L,54073L,54074L,54075L,54076L,54077L,
8931554078L,54079L,54080L,54081L,54082L,54083L,54084L,54085L,54086L,54087L,
8931654088L,54089L,54090L,54091L,54092L,54093L,54094L,54095L,54096L,54097L,
8931754098L,54099L,54100L,54101L,54102L,54103L,54104L,54105L,54106L,54107L,
8931854108L,54109L,54110L,54111L,54112L,54113L,54114L,54115L,54116L,54117L,
8931954118L,54119L,54120L,54121L,54122L,54123L,54124L,54125L,54126L,54127L,
8932054128L,54129L,54130L,54131L,54132L,54133L,54134L,54135L,54136L,54137L,
8932154138L,54139L,54140L,54141L,54142L,54143L,54144L,54145L,54146L,54147L,
8932254148L,54149L,54150L,54151L,54152L,54153L,54154L,54155L,54156L,54157L,
8932354158L,54159L,54160L,54161L,54162L,54163L,54164L,54165L,54166L,54167L,
8932454168L,54169L,54170L,54171L,54172L,54173L,54174L,54175L,54176L,54177L,
8932554178L,54179L,54180L,54181L,54182L,54183L,54184L,54185L,54186L,54187L,
8932654188L,54189L,54190L,54191L,54192L,54193L,54194L,54195L,54196L,54197L,
8932754198L,54199L,54200L,54201L,54202L,54203L,54204L,54205L,54206L,54207L,
8932854208L,54209L,54210L,54211L,54212L,54213L,54214L,54215L,54216L,54217L,
8932954218L,54219L,54220L,54221L,54222L,54223L,54224L,54225L,54226L,54227L,
8933054228L,54229L,54230L,54231L,54232L,54233L,54234L,54235L,54236L,54237L,
8933154238L,54239L,54240L,54241L,54242L,54243L,54244L,54245L,54246L,54247L,
8933254248L,54249L,54250L,54251L,54252L,54253L,54254L,54255L,54256L,54257L,
8933354258L,54259L,54260L,54261L,54262L,54263L,54264L,54265L,54266L,54267L,
8933454268L,54269L,54270L,54271L,54272L,54273L,54274L,54275L,54276L,54277L,
8933554278L,54279L,54280L,54281L,54282L,54283L,54284L,54285L,54286L,54287L,
8933654288L,54289L,54290L,54291L,54292L,54293L,54294L,54295L,54296L,54297L,
8933754298L,54299L,54300L,54301L,54302L,54303L,54304L,54305L,54306L,54307L,
8933854308L,54309L,54310L,54311L,54312L,54313L,54314L,54315L,54316L,54317L,
8933954318L,54319L,54320L,54321L,54322L,54323L,54324L,54325L,54326L,54327L,
8934054328L,54329L,54330L,54331L,54332L,54333L,54334L,54335L,54336L,54337L,
8934154338L,54339L,54340L,54341L,54342L,54343L,54344L,54345L,54346L,54347L,
8934254348L,54349L,54350L,54351L,54352L,54353L,54354L,54355L,54356L,54357L,
8934354358L,54359L,54360L,54361L,54362L,54363L,54364L,54365L,54366L,54367L,
8934454368L,54369L,54370L,54371L,54372L,54373L,54374L,54375L,54376L,54377L,
8934554378L,54379L,54380L,54381L,54382L,54383L,54384L,54385L,54386L,54387L,
8934654388L,54389L,54390L,54391L,54392L,54393L,54394L,54395L,54396L,54397L,
8934754398L,54399L,54400L,54401L,54402L,54403L,54404L,54405L,54406L,54407L,
8934854408L,54409L,54410L,54411L,54412L,54413L,54414L,54415L,54416L,54417L,
8934954418L,54419L,54420L,54421L,54422L,54423L,54424L,54425L,54426L,54427L,
8935054428L,54429L,54430L,54431L,54432L,54433L,54434L,54435L,54436L,54437L,
8935154438L,54439L,54440L,54441L,54442L,54443L,54444L,54445L,54446L,54447L,
8935254448L,54449L,54450L,54451L,54452L,54453L,54454L,54455L,54456L,54457L,
8935354458L,54459L,54460L,54461L,54462L,54463L,54464L,54465L,54466L,54467L,
8935454468L,54469L,54470L,54471L,54472L,54473L,54474L,54475L,54476L,54477L,
8935554478L,54479L,54480L,54481L,54482L,54483L,54484L,54485L,54486L,54487L,
8935654488L,54489L,54490L,54491L,54492L,54493L,54494L,54495L,54496L,54497L,
8935754498L,54499L,54500L,54501L,54502L,54503L,54504L,54505L,54506L,54507L,
8935854508L,54509L,54510L,54511L,54512L,54513L,54514L,54515L,54516L,54517L,
8935954518L,54519L,54520L,54521L,54522L,54523L,54524L,54525L,54526L,54527L,
8936054528L,54529L,54530L,54531L,54532L,54533L,54534L,54535L,54536L,54537L,
8936154538L,54539L,54540L,54541L,54542L,54543L,54544L,54545L,54546L,54547L,
8936254548L,54549L,54550L,54551L,54552L,54553L,54554L,54555L,54556L,54557L,
8936354558L,54559L,54560L,54561L,54562L,54563L,54564L,54565L,54566L,54567L,
8936454568L,54569L,54570L,54571L,54572L,54573L,54574L,54575L,54576L,54577L,
8936554578L,54579L,54580L,54581L,54582L,54583L,54584L,54585L,54586L,54587L,
8936654588L,54589L,54590L,54591L,54592L,54593L,54594L,54595L,54596L,54597L,
8936754598L,54599L,54600L,54601L,54602L,54603L,54604L,54605L,54606L,54607L,
8936854608L,54609L,54610L,54611L,54612L,54613L,54614L,54615L,54616L,54617L,
8936954618L,54619L,54620L,54621L,54622L,54623L,54624L,54625L,54626L,54627L,
8937054628L,54629L,54630L,54631L,54632L,54633L,54634L,54635L,54636L,54637L,
8937154638L,54639L,54640L,54641L,54642L,54643L,54644L,54645L,54646L,54647L,
8937254648L,54649L,54650L,54651L,54652L,54653L,54654L,54655L,54656L,54657L,
8937354658L,54659L,54660L,54661L,54662L,54663L,54664L,54665L,54666L,54667L,
8937454668L,54669L,54670L,54671L,54672L,54673L,54674L,54675L,54676L,54677L,
8937554678L,54679L,54680L,54681L,54682L,54683L,54684L,54685L,54686L,54687L,
8937654688L,54689L,54690L,54691L,54692L,54693L,54694L,54695L,54696L,54697L,
8937754698L,54699L,54700L,54701L,54702L,54703L,54704L,54705L,54706L,54707L,
8937854708L,54709L,54710L,54711L,54712L,54713L,54714L,54715L,54716L,54717L,
8937954718L,54719L,54720L,54721L,54722L,54723L,54724L,54725L,54726L,54727L,
8938054728L,54729L,54730L,54731L,54732L,54733L,54734L,54735L,54736L,54737L,
8938154738L,54739L,54740L,54741L,54742L,54743L,54744L,54745L,54746L,54747L,
8938254748L,54749L,54750L,54751L,54752L,54753L,54754L,54755L,54756L,54757L,
8938354758L,54759L,54760L,54761L,54762L,54763L,54764L,54765L,54766L,54767L,
8938454768L,54769L,54770L,54771L,54772L,54773L,54774L,54775L,54776L,54777L,
8938554778L,54779L,54780L,54781L,54782L,54783L,54784L,54785L,54786L,54787L,
8938654788L,54789L,54790L,54791L,54792L,54793L,54794L,54795L,54796L,54797L,
8938754798L,54799L,54800L,54801L,54802L,54803L,54804L,54805L,54806L,54807L,
8938854808L,54809L,54810L,54811L,54812L,54813L,54814L,54815L,54816L,54817L,
8938954818L,54819L,54820L,54821L,54822L,54823L,54824L,54825L,54826L,54827L,
8939054828L,54829L,54830L,54831L,54832L,54833L,54834L,54835L,54836L,54837L,
8939154838L,54839L,54840L,54841L,54842L,54843L,54844L,54845L,54846L,54847L,
8939254848L,54849L,54850L,54851L,54852L,54853L,54854L,54855L,54856L,54857L,
8939354858L,54859L,54860L,54861L,54862L,54863L,54864L,54865L,54866L,54867L,
8939454868L,54869L,54870L,54871L,54872L,54873L,54874L,54875L,54876L,54877L,
8939554878L,54879L,54880L,54881L,54882L,54883L,54884L,54885L,54886L,54887L,
8939654888L,54889L,54890L,54891L,54892L,54893L,54894L,54895L,54896L,54897L,
8939754898L,54899L,54900L,54901L,54902L,54903L,54904L,54905L,54906L,54907L,
8939854908L,54909L,54910L,54911L,54912L,54913L,54914L,54915L,54916L,54917L,
8939954918L,54919L,54920L,54921L,54922L,54923L,54924L,54925L,54926L,54927L,
8940054928L,54929L,54930L,54931L,54932L,54933L,54934L,54935L,54936L,54937L,
8940154938L,54939L,54940L,54941L,54942L,54943L,54944L,54945L,54946L,54947L,
8940254948L,54949L,54950L,54951L,54952L,54953L,54954L,54955L,54956L,54957L,
8940354958L,54959L,54960L,54961L,54962L,54963L,54964L,54965L,54966L,54967L,
8940454968L,54969L,54970L,54971L,54972L,54973L,54974L,54975L,54976L,54977L,
8940554978L,54979L,54980L,54981L,54982L,54983L,54984L,54985L,54986L,54987L,
8940654988L,54989L,54990L,54991L,54992L,54993L,54994L,54995L,54996L,54997L,
8940754998L,54999L,55000L,55001L,55002L,55003L,55004L,55005L,55006L,55007L,
8940855008L,55009L,55010L,55011L,55012L,55013L,55014L,55015L,55016L,55017L,
8940955018L,55019L,55020L,55021L,55022L,55023L,55024L,55025L,55026L,55027L,
8941055028L,55029L,55030L,55031L,55032L,55033L,55034L,55035L,55036L,55037L,
8941155038L,55039L,55040L,55041L,55042L,55043L,55044L,55045L,55046L,55047L,
8941255048L,55049L,55050L,55051L,55052L,55053L,55054L,55055L,55056L,55057L,
8941355058L,55059L,55060L,55061L,55062L,55063L,55064L,55065L,55066L,55067L,
8941455068L,55069L,55070L,55071L,55072L,55073L,55074L,55075L,55076L,55077L,
8941555078L,55079L,55080L,55081L,55082L,55083L,55084L,55085L,55086L,55087L,
8941655088L,55089L,55090L,55091L,55092L,55093L,55094L,55095L,55096L,55097L,
8941755098L,55099L,55100L,55101L,55102L,55103L,55104L,55105L,55106L,55107L,
8941855108L,55109L,55110L,55111L,55112L,55113L,55114L,55115L,55116L,55117L,
8941955118L,55119L,55120L,55121L,55122L,55123L,55124L,55125L,55126L,55127L,
8942055128L,55129L,55130L,55131L,55132L,55133L,55134L,55135L,55136L,55137L,
8942155138L,55139L,55140L,55141L,55142L,55143L,55144L,55145L,55146L,55147L,
8942255148L,55149L,55150L,55151L,55152L,55153L,55154L,55155L,55156L,55157L,
8942355158L,55159L,55160L,55161L,55162L,55163L,55164L,55165L,55166L,55167L,
8942455168L,55169L,55170L,55171L,55172L,55173L,55174L,55175L,55176L,55177L,
8942555178L,55179L,55180L,55181L,55182L,55183L,55184L,55185L,55186L,55187L,
8942655188L,55189L,55190L,55191L,55192L,55193L,55194L,55195L,55196L,55197L,
8942755198L,55199L,55200L,55201L,55202L,55203L,55204L,55205L,55206L,55207L,
8942855208L,55209L,55210L,55211L,55212L,55213L,55214L,55215L,55216L,55217L,
8942955218L,55219L,55220L,55221L,55222L,55223L,55224L,55225L,55226L,55227L,
8943055228L,55229L,55230L,55231L,55232L,55233L,55234L,55235L,55236L,55237L,
8943155238L,55239L,55240L,55241L,55242L,55243L,55244L,55245L,55246L,55247L,
8943255248L,55249L,55250L,55251L,55252L,55253L,55254L,55255L,55256L,55257L,
8943355258L,55259L,55260L,55261L,55262L,55263L,55264L,55265L,55266L,55267L,
8943455268L,55269L,55270L,55271L,55272L,55273L,55274L,55275L,55276L,55277L,
8943555278L,55279L,55280L,55281L,55282L,55283L,55284L,55285L,55286L,55287L,
8943655288L,55289L,55290L,55291L,55292L,55293L,55294L,55295L,55296L,55297L,
8943755298L,55299L,55300L,55301L,55302L,55303L,55304L,55305L,55306L,55307L,
8943855308L,55309L,55310L,55311L,55312L,55313L,55314L,55315L,55316L,55317L,
8943955318L,55319L,55320L,55321L,55322L,55323L,55324L,55325L,55326L,55327L,
8944055328L,55329L,55330L,55331L,55332L,55333L,55334L,55335L,55336L,55337L,
8944155338L,55339L,55340L,55341L,55342L,55343L,55344L,55345L,55346L,55347L,
8944255348L,55349L,55350L,55351L,55352L,55353L,55354L,55355L,55356L,55357L,
8944355358L,55359L,55360L,55361L,55362L,55363L,55364L,55365L,55366L,55367L,
8944455368L,55369L,55370L,55371L,55372L,55373L,55374L,55375L,55376L,55377L,
8944555378L,55379L,55380L,55381L,55382L,55383L,55384L,55385L,55386L,55387L,
8944655388L,55389L,55390L,55391L,55392L,55393L,55394L,55395L,55396L,55397L,
8944755398L,55399L,55400L,55401L,55402L,55403L,55404L,55405L,55406L,55407L,
8944855408L,55409L,55410L,55411L,55412L,55413L,55414L,55415L,55416L,55417L,
8944955418L,55419L,55420L,55421L,55422L,55423L,55424L,55425L,55426L,55427L,
8945055428L,55429L,55430L,55431L,55432L,55433L,55434L,55435L,55436L,55437L,
8945155438L,55439L,55440L,55441L,55442L,55443L,55444L,55445L,55446L,55447L,
8945255448L,55449L,55450L,55451L,55452L,55453L,55454L,55455L,55456L,55457L,
8945355458L,55459L,55460L,55461L,55462L,55463L,55464L,55465L,55466L,55467L,
8945455468L,55469L,55470L,55471L,55472L,55473L,55474L,55475L,55476L,55477L,
8945555478L,55479L,55480L,55481L,55482L,55483L,55484L,55485L,55486L,55487L,
8945655488L,55489L,55490L,55491L,55492L,55493L,55494L,55495L,55496L,55497L,
8945755498L,55499L,55500L,55501L,55502L,55503L,55504L,55505L,55506L,55507L,
8945855508L,55509L,55510L,55511L,55512L,55513L,55514L,55515L,55516L,55517L,
8945955518L,55519L,55520L,55521L,55522L,55523L,55524L,55525L,55526L,55527L,
8946055528L,55529L,55530L,55531L,55532L,55533L,55534L,55535L,55536L,55537L,
8946155538L,55539L,55540L,55541L,55542L,55543L,55544L,55545L,55546L,55547L,
8946255548L,55549L,55550L,55551L,55552L,55553L,55554L,55555L,55556L,55557L,
8946355558L,55559L,55560L,55561L,55562L,55563L,55564L,55565L,55566L,55567L,
8946455568L,55569L,55570L,55571L,55572L,55573L,55574L,55575L,55576L,55577L,
8946555578L,55579L,55580L,55581L,55582L,55583L,55584L,55585L,55586L,55587L,
8946655588L,55589L,55590L,55591L,55592L,55593L,55594L,55595L,55596L,55597L,
8946755598L,55599L,55600L,55601L,55602L,55603L,55604L,55605L,55606L,55607L,
8946855608L,55609L,55610L,55611L,55612L,55613L,55614L,55615L,55616L,55617L,
8946955618L,55619L,55620L,55621L,55622L,55623L,55624L,55625L,55626L,55627L,
8947055628L,55629L,55630L,55631L,55632L,55633L,55634L,55635L,55636L,55637L,
8947155638L,55639L,55640L,55641L,55642L,55643L,55644L,55645L,55646L,55647L,
8947255648L,55649L,55650L,55651L,55652L,55653L,55654L,55655L,55656L,55657L,
8947355658L,55659L,55660L,55661L,55662L,55663L,55664L,55665L,55666L,55667L,
8947455668L,55669L,55670L,55671L,55672L,55673L,55674L,55675L,55676L,55677L,
8947555678L,55679L,55680L,55681L,55682L,55683L,55684L,55685L,55686L,55687L,
8947655688L,55689L,55690L,55691L,55692L,55693L,55694L,55695L,55696L,55697L,
8947755698L,55699L,55700L,55701L,55702L,55703L,55704L,55705L,55706L,55707L,
8947855708L,55709L,55710L,55711L,55712L,55713L,55714L,55715L,55716L,55717L,
8947955718L,55719L,55720L,55721L,55722L,55723L,55724L,55725L,55726L,55727L,
8948055728L,55729L,55730L,55731L,55732L,55733L,55734L,55735L,55736L,55737L,
8948155738L,55739L,55740L,55741L,55742L,55743L,55744L,55745L,55746L,55747L,
8948255748L,55749L,55750L,55751L,55752L,55753L,55754L,55755L,55756L,55757L,
8948355758L,55759L,55760L,55761L,55762L,55763L,55764L,55765L,55766L,55767L,
8948455768L,55769L,55770L,55771L,55772L,55773L,55774L,55775L,55776L,55777L,
8948555778L,55779L,55780L,55781L,55782L,55783L,55784L,55785L,55786L,55787L,
8948655788L,55789L,55790L,55791L,55792L,55793L,55794L,55795L,55796L,55797L,
8948755798L,55799L,55800L,55801L,55802L,55803L,55804L,55805L,55806L,55807L,
8948855808L,55809L,55810L,55811L,55812L,55813L,55814L,55815L,55816L,55817L,
8948955818L,55819L,55820L,55821L,55822L,55823L,55824L,55825L,55826L,55827L,
8949055828L,55829L,55830L,55831L,55832L,55833L,55834L,55835L,55836L,55837L,
8949155838L,55839L,55840L,55841L,55842L,55843L,55844L,55845L,55846L,55847L,
8949255848L,55849L,55850L,55851L,55852L,55853L,55854L,55855L,55856L,55857L,
8949355858L,55859L,55860L,55861L,55862L,55863L,55864L,55865L,55866L,55867L,
8949455868L,55869L,55870L,55871L,55872L,55873L,55874L,55875L,55876L,55877L,
8949555878L,55879L,55880L,55881L,55882L,55883L,55884L,55885L,55886L,55887L,
8949655888L,55889L,55890L,55891L,55892L,55893L,55894L,55895L,55896L,55897L,
8949755898L,55899L,55900L,55901L,55902L,55903L,55904L,55905L,55906L,55907L,
8949855908L,55909L,55910L,55911L,55912L,55913L,55914L,55915L,55916L,55917L,
8949955918L,55919L,55920L,55921L,55922L,55923L,55924L,55925L,55926L,55927L,
8950055928L,55929L,55930L,55931L,55932L,55933L,55934L,55935L,55936L,55937L,
8950155938L,55939L,55940L,55941L,55942L,55943L,55944L,55945L,55946L,55947L,
8950255948L,55949L,55950L,55951L,55952L,55953L,55954L,55955L,55956L,55957L,
8950355958L,55959L,55960L,55961L,55962L,55963L,55964L,55965L,55966L,55967L,
8950455968L,55969L,55970L,55971L,55972L,55973L,55974L,55975L,55976L,55977L,
8950555978L,55979L,55980L,55981L,55982L,55983L,55984L,55985L,55986L,55987L,
8950655988L,55989L,55990L,55991L,55992L,55993L,55994L,55995L,55996L,55997L,
8950755998L,55999L,56000L,56001L,56002L,56003L,56004L,56005L,56006L,56007L,
8950856008L,56009L,56010L,56011L,56012L,56013L,56014L,56015L,56016L,56017L,
8950956018L,56019L,56020L,56021L,56022L,56023L,56024L,56025L,56026L,56027L,
8951056028L,56029L,56030L,56031L,56032L,56033L,56034L,56035L,56036L,56037L,
8951156038L,56039L,56040L,56041L,56042L,56043L,56044L,56045L,56046L,56047L,
8951256048L,56049L,56050L,56051L,56052L,56053L,56054L,56055L,56056L,56057L,
8951356058L,56059L,56060L,56061L,56062L,56063L,56064L,56065L,56066L,56067L,
8951456068L,56069L,56070L,56071L,56072L,56073L,56074L,56075L,56076L,56077L,
8951556078L,56079L,56080L,56081L,56082L,56083L,56084L,56085L,56086L,56087L,
8951656088L,56089L,56090L,56091L,56092L,56093L,56094L,56095L,56096L,56097L,
8951756098L,56099L,56100L,56101L,56102L,56103L,56104L,56105L,56106L,56107L,
8951856108L,56109L,56110L,56111L,56112L,56113L,56114L,56115L,56116L,56117L,
8951956118L,56119L,56120L,56121L,56122L,56123L,56124L,56125L,56126L,56127L,
8952056128L,56129L,56130L,56131L,56132L,56133L,56134L,56135L,56136L,56137L,
8952156138L,56139L,56140L,56141L,56142L,56143L,56144L,56145L,56146L,56147L,
8952256148L,56149L,56150L,56151L,56152L,56153L,56154L,56155L,56156L,56157L,
8952356158L,56159L,56160L,56161L,56162L,56163L,56164L,56165L,56166L,56167L,
8952456168L,56169L,56170L,56171L,56172L,56173L,56174L,56175L,56176L,56177L,
8952556178L,56179L,56180L,56181L,56182L,56183L,56184L,56185L,56186L,56187L,
8952656188L,56189L,56190L,56191L,56192L,56193L,56194L,56195L,56196L,56197L,
8952756198L,56199L,56200L,56201L,56202L,56203L,56204L,56205L,56206L,56207L,
8952856208L,56209L,56210L,56211L,56212L,56213L,56214L,56215L,56216L,56217L,
8952956218L,56219L,56220L,56221L,56222L,56223L,56224L,56225L,56226L,56227L,
8953056228L,56229L,56230L,56231L,56232L,56233L,56234L,56235L,56236L,56237L,
8953156238L,56239L,56240L,56241L,56242L,56243L,56244L,56245L,56246L,56247L,
8953256248L,56249L,56250L,56251L,56252L,56253L,56254L,56255L,56256L,56257L,
8953356258L,56259L,56260L,56261L,56262L,56263L,56264L,56265L,56266L,56267L,
8953456268L,56269L,56270L,56271L,56272L,56273L,56274L,56275L,56276L,56277L,
8953556278L,56279L,56280L,56281L,56282L,56283L,56284L,56285L,56286L,56287L,
8953656288L,56289L,56290L,56291L,56292L,56293L,56294L,56295L,56296L,56297L,
8953756298L,56299L,56300L,56301L,56302L,56303L,56304L,56305L,56306L,56307L,
8953856308L,56309L,56310L,56311L,56312L,56313L,56314L,56315L,56316L,56317L,
8953956318L,56319L,56320L,56321L,56322L,56323L,56324L,56325L,56326L,56327L,
8954056328L,56329L,56330L,56331L,56332L,56333L,56334L,56335L,56336L,56337L,
8954156338L,56339L,56340L,56341L,56342L,56343L,56344L,56345L,56346L,56347L,
8954256348L,56349L,56350L,56351L,56352L,56353L,56354L,56355L,56356L,56357L,
8954356358L,56359L,56360L,56361L,56362L,56363L,56364L,56365L,56366L,56367L,
8954456368L,56369L,56370L,56371L,56372L,56373L,56374L,56375L,56376L,56377L,
8954556378L,56379L,56380L,56381L,56382L,56383L,56384L,56385L,56386L,56387L,
8954656388L,56389L,56390L,56391L,56392L,56393L,56394L,56395L,56396L,56397L,
8954756398L,56399L,56400L,56401L,56402L,56403L,56404L,56405L,56406L,56407L,
8954856408L,56409L,56410L,56411L,56412L,56413L,56414L,56415L,56416L,56417L,
8954956418L,56419L,56420L,56421L,56422L,56423L,56424L,56425L,56426L,56427L,
8955056428L,56429L,56430L,56431L,56432L,56433L,56434L,56435L,56436L,56437L,
8955156438L,56439L,56440L,56441L,56442L,56443L,56444L,56445L,56446L,56447L,
8955256448L,56449L,56450L,56451L,56452L,56453L,56454L,56455L,56456L,56457L,
8955356458L,56459L,56460L,56461L,56462L,56463L,56464L,56465L,56466L,56467L,
8955456468L,56469L,56470L,56471L,56472L,56473L,56474L,56475L,56476L,56477L,
8955556478L,56479L,56480L,56481L,56482L,56483L,56484L,56485L,56486L,56487L,
8955656488L,56489L,56490L,56491L,56492L,56493L,56494L,56495L,56496L,56497L,
8955756498L,56499L,56500L,56501L,56502L,56503L,56504L,56505L,56506L,56507L,
8955856508L,56509L,56510L,56511L,56512L,56513L,56514L,56515L,56516L,56517L,
8955956518L,56519L,56520L,56521L,56522L,56523L,56524L,56525L,56526L,56527L,
8956056528L,56529L,56530L,56531L,56532L,56533L,56534L,56535L,56536L,56537L,
8956156538L,56539L,56540L,56541L,56542L,56543L,56544L,56545L,56546L,56547L,
8956256548L,56549L,56550L,56551L,56552L,56553L,56554L,56555L,56556L,56557L,
8956356558L,56559L,56560L,56561L,56562L,56563L,56564L,56565L,56566L,56567L,
8956456568L,56569L,56570L,56571L,56572L,56573L,56574L,56575L,56576L,56577L,
8956556578L,56579L,56580L,56581L,56582L,56583L,56584L,56585L,56586L,56587L,
8956656588L,56589L,56590L,56591L,56592L,56593L,56594L,56595L,56596L,56597L,
8956756598L,56599L,56600L,56601L,56602L,56603L,56604L,56605L,56606L,56607L,
8956856608L,56609L,56610L,56611L,56612L,56613L,56614L,56615L,56616L,56617L,
8956956618L,56619L,56620L,56621L,56622L,56623L,56624L,56625L,56626L,56627L,
8957056628L,56629L,56630L,56631L,56632L,56633L,56634L,56635L,56636L,56637L,
8957156638L,56639L,56640L,56641L,56642L,56643L,56644L,56645L,56646L,56647L,
8957256648L,56649L,56650L,56651L,56652L,56653L,56654L,56655L,56656L,56657L,
8957356658L,56659L,56660L,56661L,56662L,56663L,56664L,56665L,56666L,56667L,
8957456668L,56669L,56670L,56671L,56672L,56673L,56674L,56675L,56676L,56677L,
8957556678L,56679L,56680L,56681L,56682L,56683L,56684L,56685L,56686L,56687L,
8957656688L,56689L,56690L,56691L,56692L,56693L,56694L,56695L,56696L,56697L,
8957756698L,56699L,56700L,56701L,56702L,56703L,56704L,56705L,56706L,56707L,
8957856708L,56709L,56710L,56711L,56712L,56713L,56714L,56715L,56716L,56717L,
8957956718L,56719L,56720L,56721L,56722L,56723L,56724L,56725L,56726L,56727L,
8958056728L,56729L,56730L,56731L,56732L,56733L,56734L,56735L,56736L,56737L,
8958156738L,56739L,56740L,56741L,56742L,56743L,56744L,56745L,56746L,56747L,
8958256748L,56749L,56750L,56751L,56752L,56753L,56754L,56755L,56756L,56757L,
8958356758L,56759L,56760L,56761L,56762L,56763L,56764L,56765L,56766L,56767L,
8958456768L,56769L,56770L,56771L,56772L,56773L,56774L,56775L,56776L,56777L,
8958556778L,56779L,56780L,56781L,56782L,56783L,56784L,56785L,56786L,56787L,
8958656788L,56789L,56790L,56791L,56792L,56793L,56794L,56795L,56796L,56797L,
8958756798L,56799L,56800L,56801L,56802L,56803L,56804L,56805L,56806L,56807L,
8958856808L,56809L,56810L,56811L,56812L,56813L,56814L,56815L,56816L,56817L,
8958956818L,56819L,56820L,56821L,56822L,56823L,56824L,56825L,56826L,56827L,
8959056828L,56829L,56830L,56831L,56832L,56833L,56834L,56835L,56836L,56837L,
8959156838L,56839L,56840L,56841L,56842L,56843L,56844L,56845L,56846L,56847L,
8959256848L,56849L,56850L,56851L,56852L,56853L,56854L,56855L,56856L,56857L,
8959356858L,56859L,56860L,56861L,56862L,56863L,56864L,56865L,56866L,56867L,
8959456868L,56869L,56870L,56871L,56872L,56873L,56874L,56875L,56876L,56877L,
8959556878L,56879L,56880L,56881L,56882L,56883L,56884L,56885L,56886L,56887L,
8959656888L,56889L,56890L,56891L,56892L,56893L,56894L,56895L,56896L,56897L,
8959756898L,56899L,56900L,56901L,56902L,56903L,56904L,56905L,56906L,56907L,
8959856908L,56909L,56910L,56911L,56912L,56913L,56914L,56915L,56916L,56917L,
8959956918L,56919L,56920L,56921L,56922L,56923L,56924L,56925L,56926L,56927L,
8960056928L,56929L,56930L,56931L,56932L,56933L,56934L,56935L,56936L,56937L,
8960156938L,56939L,56940L,56941L,56942L,56943L,56944L,56945L,56946L,56947L,
8960256948L,56949L,56950L,56951L,56952L,56953L,56954L,56955L,56956L,56957L,
8960356958L,56959L,56960L,56961L,56962L,56963L,56964L,56965L,56966L,56967L,
8960456968L,56969L,56970L,56971L,56972L,56973L,56974L,56975L,56976L,56977L,
8960556978L,56979L,56980L,56981L,56982L,56983L,56984L,56985L,56986L,56987L,
8960656988L,56989L,56990L,56991L,56992L,56993L,56994L,56995L,56996L,56997L,
8960756998L,56999L,57000L,57001L,57002L,57003L,57004L,57005L,57006L,57007L,
8960857008L,57009L,57010L,57011L,57012L,57013L,57014L,57015L,57016L,57017L,
8960957018L,57019L,57020L,57021L,57022L,57023L,57024L,57025L,57026L,57027L,
8961057028L,57029L,57030L,57031L,57032L,57033L,57034L,57035L,57036L,57037L,
8961157038L,57039L,57040L,57041L,57042L,57043L,57044L,57045L,57046L,57047L,
8961257048L,57049L,57050L,57051L,57052L,57053L,57054L,57055L,57056L,57057L,
8961357058L,57059L,57060L,57061L,57062L,57063L,57064L,57065L,57066L,57067L,
8961457068L,57069L,57070L,57071L,57072L,57073L,57074L,57075L,57076L,57077L,
8961557078L,57079L,57080L,57081L,57082L,57083L,57084L,57085L,57086L,57087L,
8961657088L,57089L,57090L,57091L,57092L,57093L,57094L,57095L,57096L,57097L,
8961757098L,57099L,57100L,57101L,57102L,57103L,57104L,57105L,57106L,57107L,
8961857108L,57109L,57110L,57111L,57112L,57113L,57114L,57115L,57116L,57117L,
8961957118L,57119L,57120L,57121L,57122L,57123L,57124L,57125L,57126L,57127L,
8962057128L,57129L,57130L,57131L,57132L,57133L,57134L,57135L,57136L,57137L,
8962157138L,57139L,57140L,57141L,57142L,57143L,57144L,57145L,57146L,57147L,
8962257148L,57149L,57150L,57151L,57152L,57153L,57154L,57155L,57156L,57157L,
8962357158L,57159L,57160L,57161L,57162L,57163L,57164L,57165L,57166L,57167L,
8962457168L,57169L,57170L,57171L,57172L,57173L,57174L,57175L,57176L,57177L,
8962557178L,57179L,57180L,57181L,57182L,57183L,57184L,57185L,57186L,57187L,
8962657188L,57189L,57190L,57191L,57192L,57193L,57194L,57195L,57196L,57197L,
8962757198L,57199L,57200L,57201L,57202L,57203L,57204L,57205L,57206L,57207L,
8962857208L,57209L,57210L,57211L,57212L,57213L,57214L,57215L,57216L,57217L,
8962957218L,57219L,57220L,57221L,57222L,57223L,57224L,57225L,57226L,57227L,
8963057228L,57229L,57230L,57231L,57232L,57233L,57234L,57235L,57236L,57237L,
8963157238L,57239L,57240L,57241L,57242L,57243L,57244L,57245L,57246L,57247L,
8963257248L,57249L,57250L,57251L,57252L,57253L,57254L,57255L,57256L,57257L,
8963357258L,57259L,57260L,57261L,57262L,57263L,57264L,57265L,57266L,57267L,
8963457268L,57269L,57270L,57271L,57272L,57273L,57274L,57275L,57276L,57277L,
8963557278L,57279L,57280L,57281L,57282L,57283L,57284L,57285L,57286L,57287L,
8963657288L,57289L,57290L,57291L,57292L,57293L,57294L,57295L,57296L,57297L,
8963757298L,57299L,57300L,57301L,57302L,57303L,57304L,57305L,57306L,57307L,
8963857308L,57309L,57310L,57311L,57312L,57313L,57314L,57315L,57316L,57317L,
8963957318L,57319L,57320L,57321L,57322L,57323L,57324L,57325L,57326L,57327L,
8964057328L,57329L,57330L,57331L,57332L,57333L,57334L,57335L,57336L,57337L,
8964157338L,57339L,57340L,57341L,57342L,57343L,57344L,57345L,57346L,57347L,
8964257348L,57349L,57350L,57351L,57352L,57353L,57354L,57355L,57356L,57357L,
8964357358L,57359L,57360L,57361L,57362L,57363L,57364L,57365L,57366L,57367L,
8964457368L,57369L,57370L,57371L,57372L,57373L,57374L,57375L,57376L,57377L,
8964557378L,57379L,57380L,57381L,57382L,57383L,57384L,57385L,57386L,57387L,
8964657388L,57389L,57390L,57391L,57392L,57393L,57394L,57395L,57396L,57397L,
8964757398L,57399L,57400L,57401L,57402L,57403L,57404L,57405L,57406L,57407L,
8964857408L,57409L,57410L,57411L,57412L,57413L,57414L,57415L,57416L,57417L,
8964957418L,57419L,57420L,57421L,57422L,57423L,57424L,57425L,57426L,57427L,
8965057428L,57429L,57430L,57431L,57432L,57433L,57434L,57435L,57436L,57437L,
8965157438L,57439L,57440L,57441L,57442L,57443L,57444L,57445L,57446L,57447L,
8965257448L,57449L,57450L,57451L,57452L,57453L,57454L,57455L,57456L,57457L,
8965357458L,57459L,57460L,57461L,57462L,57463L,57464L,57465L,57466L,57467L,
8965457468L,57469L,57470L,57471L,57472L,57473L,57474L,57475L,57476L,57477L,
8965557478L,57479L,57480L,57481L,57482L,57483L,57484L,57485L,57486L,57487L,
8965657488L,57489L,57490L,57491L,57492L,57493L,57494L,57495L,57496L,57497L,
8965757498L,57499L,57500L,57501L,57502L,57503L,57504L,57505L,57506L,57507L,
8965857508L,57509L,57510L,57511L,57512L,57513L,57514L,57515L,57516L,57517L,
8965957518L,57519L,57520L,57521L,57522L,57523L,57524L,57525L,57526L,57527L,
8966057528L,57529L,57530L,57531L,57532L,57533L,57534L,57535L,57536L,57537L,
8966157538L,57539L,57540L,57541L,57542L,57543L,57544L,57545L,57546L,57547L,
8966257548L,57549L,57550L,57551L,57552L,57553L,57554L,57555L,57556L,57557L,
8966357558L,57559L,57560L,57561L,57562L,57563L,57564L,57565L,57566L,57567L,
8966457568L,57569L,57570L,57571L,57572L,57573L,57574L,57575L,57576L,57577L,
8966557578L,57579L,57580L,57581L,57582L,57583L,57584L,57585L,57586L,57587L,
8966657588L,57589L,57590L,57591L,57592L,57593L,57594L,57595L,57596L,57597L,
8966757598L,57599L,57600L,57601L,57602L,57603L,57604L,57605L,57606L,57607L,
8966857608L,57609L,57610L,57611L,57612L,57613L,57614L,57615L,57616L,57617L,
8966957618L,57619L,57620L,57621L,57622L,57623L,57624L,57625L,57626L,57627L,
8967057628L,57629L,57630L,57631L,57632L,57633L,57634L,57635L,57636L,57637L,
8967157638L,57639L,57640L,57641L,57642L,57643L,57644L,57645L,57646L,57647L,
8967257648L,57649L,57650L,57651L,57652L,57653L,57654L,57655L,57656L,57657L,
8967357658L,57659L,57660L,57661L,57662L,57663L,57664L,57665L,57666L,57667L,
8967457668L,57669L,57670L,57671L,57672L,57673L,57674L,57675L,57676L,57677L,
8967557678L,57679L,57680L,57681L,57682L,57683L,57684L,57685L,57686L,57687L,
8967657688L,57689L,57690L,57691L,57692L,57693L,57694L,57695L,57696L,57697L,
8967757698L,57699L,57700L,57701L,57702L,57703L,57704L,57705L,57706L,57707L,
8967857708L,57709L,57710L,57711L,57712L,57713L,57714L,57715L,57716L,57717L,
8967957718L,57719L,57720L,57721L,57722L,57723L,57724L,57725L,57726L,57727L,
8968057728L,57729L,57730L,57731L,57732L,57733L,57734L,57735L,57736L,57737L,
8968157738L,57739L,57740L,57741L,57742L,57743L,57744L,57745L,57746L,57747L,
8968257748L,57749L,57750L,57751L,57752L,57753L,57754L,57755L,57756L,57757L,
8968357758L,57759L,57760L,57761L,57762L,57763L,57764L,57765L,57766L,57767L,
8968457768L,57769L,57770L,57771L,57772L,57773L,57774L,57775L,57776L,57777L,
8968557778L,57779L,57780L,57781L,57782L,57783L,57784L,57785L,57786L,57787L,
8968657788L,57789L,57790L,57791L,57792L,57793L,57794L,57795L,57796L,57797L,
8968757798L,57799L,57800L,57801L,57802L,57803L,57804L,57805L,57806L,57807L,
8968857808L,57809L,57810L,57811L,57812L,57813L,57814L,57815L,57816L,57817L,
8968957818L,57819L,57820L,57821L,57822L,57823L,57824L,57825L,57826L,57827L,
8969057828L,57829L,57830L,57831L,57832L,57833L,57834L,57835L,57836L,57837L,
8969157838L,57839L,57840L,57841L,57842L,57843L,57844L,57845L,57846L,57847L,
8969257848L,57849L,57850L,57851L,57852L,57853L,57854L,57855L,57856L,57857L,
8969357858L,57859L,57860L,57861L,57862L,57863L,57864L,57865L,57866L,57867L,
8969457868L,57869L,57870L,57871L,57872L,57873L,57874L,57875L,57876L,57877L,
8969557878L,57879L,57880L,57881L,57882L,57883L,57884L,57885L,57886L,57887L,
8969657888L,57889L,57890L,57891L,57892L,57893L,57894L,57895L,57896L,57897L,
8969757898L,57899L,57900L,57901L,57902L,57903L,57904L,57905L,57906L,57907L,
8969857908L,57909L,57910L,57911L,57912L,57913L,57914L,57915L,57916L,57917L,
8969957918L,57919L,57920L,57921L,57922L,57923L,57924L,57925L,57926L,57927L,
8970057928L,57929L,57930L,57931L,57932L,57933L,57934L,57935L,57936L,57937L,
8970157938L,57939L,57940L,57941L,57942L,57943L,57944L,57945L,57946L,57947L,
8970257948L,57949L,57950L,57951L,57952L,57953L,57954L,57955L,57956L,57957L,
8970357958L,57959L,57960L,57961L,57962L,57963L,57964L,57965L,57966L,57967L,
8970457968L,57969L,57970L,57971L,57972L,57973L,57974L,57975L,57976L,57977L,
8970557978L,57979L,57980L,57981L,57982L,57983L,57984L,57985L,57986L,57987L,
8970657988L,57989L,57990L,57991L,57992L,57993L,57994L,57995L,57996L,57997L,
8970757998L,57999L,58000L,58001L,58002L,58003L,58004L,58005L,58006L,58007L,
8970858008L,58009L,58010L,58011L,58012L,58013L,58014L,58015L,58016L,58017L,
8970958018L,58019L,58020L,58021L,58022L,58023L,58024L,58025L,58026L,58027L,
8971058028L,58029L,58030L,58031L,58032L,58033L,58034L,58035L,58036L,58037L,
8971158038L,58039L,58040L,58041L,58042L,58043L,58044L,58045L,58046L,58047L,
8971258048L,58049L,58050L,58051L,58052L,58053L,58054L,58055L,58056L,58057L,
8971358058L,58059L,58060L,58061L,58062L,58063L,58064L,58065L,58066L,58067L,
8971458068L,58069L,58070L,58071L,58072L,58073L,58074L,58075L,58076L,58077L,
8971558078L,58079L,58080L,58081L,58082L,58083L,58084L,58085L,58086L,58087L,
8971658088L,58089L,58090L,58091L,58092L,58093L,58094L,58095L,58096L,58097L,
8971758098L,58099L,58100L,58101L,58102L,58103L,58104L,58105L,58106L,58107L,
8971858108L,58109L,58110L,58111L,58112L,58113L,58114L,58115L,58116L,58117L,
8971958118L,58119L,58120L,58121L,58122L,58123L,58124L,58125L,58126L,58127L,
8972058128L,58129L,58130L,58131L,58132L,58133L,58134L,58135L,58136L,58137L,
8972158138L,58139L,58140L,58141L,58142L,58143L,58144L,58145L,58146L,58147L,
8972258148L,58149L,58150L,58151L,58152L,58153L,58154L,58155L,58156L,58157L,
8972358158L,58159L,58160L,58161L,58162L,58163L,58164L,58165L,58166L,58167L,
8972458168L,58169L,58170L,58171L,58172L,58173L,58174L,58175L,58176L,58177L,
8972558178L,58179L,58180L,58181L,58182L,58183L,58184L,58185L,58186L,58187L,
8972658188L,58189L,58190L,58191L,58192L,58193L,58194L,58195L,58196L,58197L,
8972758198L,58199L,58200L,58201L,58202L,58203L,58204L,58205L,58206L,58207L,
8972858208L,58209L,58210L,58211L,58212L,58213L,58214L,58215L,58216L,58217L,
8972958218L,58219L,58220L,58221L,58222L,58223L,58224L,58225L,58226L,58227L,
8973058228L,58229L,58230L,58231L,58232L,58233L,58234L,58235L,58236L,58237L,
8973158238L,58239L,58240L,58241L,58242L,58243L,58244L,58245L,58246L,58247L,
8973258248L,58249L,58250L,58251L,58252L,58253L,58254L,58255L,58256L,58257L,
8973358258L,58259L,58260L,58261L,58262L,58263L,58264L,58265L,58266L,58267L,
8973458268L,58269L,58270L,58271L,58272L,58273L,58274L,58275L,58276L,58277L,
8973558278L,58279L,58280L,58281L,58282L,58283L,58284L,58285L,58286L,58287L,
8973658288L,58289L,58290L,58291L,58292L,58293L,58294L,58295L,58296L,58297L,
8973758298L,58299L,58300L,58301L,58302L,58303L,58304L,58305L,58306L,58307L,
8973858308L,58309L,58310L,58311L,58312L,58313L,58314L,58315L,58316L,58317L,
8973958318L,58319L,58320L,58321L,58322L,58323L,58324L,58325L,58326L,58327L,
8974058328L,58329L,58330L,58331L,58332L,58333L,58334L,58335L,58336L,58337L,
8974158338L,58339L,58340L,58341L,58342L,58343L,58344L,58345L,58346L,58347L,
8974258348L,58349L,58350L,58351L,58352L,58353L,58354L,58355L,58356L,58357L,
8974358358L,58359L,58360L,58361L,58362L,58363L,58364L,58365L,58366L,58367L,
8974458368L,58369L,58370L,58371L,58372L,58373L,58374L,58375L,58376L,58377L,
8974558378L,58379L,58380L,58381L,58382L,58383L,58384L,58385L,58386L,58387L,
8974658388L,58389L,58390L,58391L,58392L,58393L,58394L,58395L,58396L,58397L,
8974758398L,58399L,58400L,58401L,58402L,58403L,58404L,58405L,58406L,58407L,
8974858408L,58409L,58410L,58411L,58412L,58413L,58414L,58415L,58416L,58417L,
8974958418L,58419L,58420L,58421L,58422L,58423L,58424L,58425L,58426L,58427L,
8975058428L,58429L,58430L,58431L,58432L,58433L,58434L,58435L,58436L,58437L,
8975158438L,58439L,58440L,58441L,58442L,58443L,58444L,58445L,58446L,58447L,
8975258448L,58449L,58450L,58451L,58452L,58453L,58454L,58455L,58456L,58457L,
8975358458L,58459L,58460L,58461L,58462L,58463L,58464L,58465L,58466L,58467L,
8975458468L,58469L,58470L,58471L,58472L,58473L,58474L,58475L,58476L,58477L,
8975558478L,58479L,58480L,58481L,58482L,58483L,58484L,58485L,58486L,58487L,
8975658488L,58489L,58490L,58491L,58492L,58493L,58494L,58495L,58496L,58497L,
8975758498L,58499L,58500L,58501L,58502L,58503L,58504L,58505L,58506L,58507L,
8975858508L,58509L,58510L,58511L,58512L,58513L,58514L,58515L,58516L,58517L,
8975958518L,58519L,58520L,58521L,58522L,58523L,58524L,58525L,58526L,58527L,
8976058528L,58529L,58530L,58531L,58532L,58533L,58534L,58535L,58536L,58537L,
8976158538L,58539L,58540L,58541L,58542L,58543L,58544L,58545L,58546L,58547L,
8976258548L,58549L,58550L,58551L,58552L,58553L,58554L,58555L,58556L,58557L,
8976358558L,58559L,58560L,58561L,58562L,58563L,58564L,58565L,58566L,58567L,
8976458568L,58569L,58570L,58571L,58572L,58573L,58574L,58575L,58576L,58577L,
8976558578L,58579L,58580L,58581L,58582L,58583L,58584L,58585L,58586L,58587L,
8976658588L,58589L,58590L,58591L,58592L,58593L,58594L,58595L,58596L,58597L,
8976758598L,58599L,58600L,58601L,58602L,58603L,58604L,58605L,58606L,58607L,
8976858608L,58609L,58610L,58611L,58612L,58613L,58614L,58615L,58616L,58617L,
8976958618L,58619L,58620L,58621L,58622L,58623L,58624L,58625L,58626L,58627L,
8977058628L,58629L,58630L,58631L,58632L,58633L,58634L,58635L,58636L,58637L,
8977158638L,58639L,58640L,58641L,58642L,58643L,58644L,58645L,58646L,58647L,
8977258648L,58649L,58650L,58651L,58652L,58653L,58654L,58655L,58656L,58657L,
8977358658L,58659L,58660L,58661L,58662L,58663L,58664L,58665L,58666L,58667L,
8977458668L,58669L,58670L,58671L,58672L,58673L,58674L,58675L,58676L,58677L,
8977558678L,58679L,58680L,58681L,58682L,58683L,58684L,58685L,58686L,58687L,
8977658688L,58689L,58690L,58691L,58692L,58693L,58694L,58695L,58696L,58697L,
8977758698L,58699L,58700L,58701L,58702L,58703L,58704L,58705L,58706L,58707L,
8977858708L,58709L,58710L,58711L,58712L,58713L,58714L,58715L,58716L,58717L,
8977958718L,58719L,58720L,58721L,58722L,58723L,58724L,58725L,58726L,58727L,
8978058728L,58729L,58730L,58731L,58732L,58733L,58734L,58735L,58736L,58737L,
8978158738L,58739L,58740L,58741L,58742L,58743L,58744L,58745L,58746L,58747L,
8978258748L,58749L,58750L,58751L,58752L,58753L,58754L,58755L,58756L,58757L,
8978358758L,58759L,58760L,58761L,58762L,58763L,58764L,58765L,58766L,58767L,
8978458768L,58769L,58770L,58771L,58772L,58773L,58774L,58775L,58776L,58777L,
8978558778L,58779L,58780L,58781L,58782L,58783L,58784L,58785L,58786L,58787L,
8978658788L,58789L,58790L,58791L,58792L,58793L,58794L,58795L,58796L,58797L,
8978758798L,58799L,58800L,58801L,58802L,58803L,58804L,58805L,58806L,58807L,
8978858808L,58809L,58810L,58811L,58812L,58813L,58814L,58815L,58816L,58817L,
8978958818L,58819L,58820L,58821L,58822L,58823L,58824L,58825L,58826L,58827L,
8979058828L,58829L,58830L,58831L,58832L,58833L,58834L,58835L,58836L,58837L,
8979158838L,58839L,58840L,58841L,58842L,58843L,58844L,58845L,58846L,58847L,
8979258848L,58849L,58850L,58851L,58852L,58853L,58854L,58855L,58856L,58857L,
8979358858L,58859L,58860L,58861L,58862L,58863L,58864L,58865L,58866L,58867L,
8979458868L,58869L,58870L,58871L,58872L,58873L,58874L,58875L,58876L,58877L,
8979558878L,58879L,58880L,58881L,58882L,58883L,58884L,58885L,58886L,58887L,
8979658888L,58889L,58890L,58891L,58892L,58893L,58894L,58895L,58896L,58897L,
8979758898L,58899L,58900L,58901L,58902L,58903L,58904L,58905L,58906L,58907L,
8979858908L,58909L,58910L,58911L,58912L,58913L,58914L,58915L,58916L,58917L,
8979958918L,58919L,58920L,58921L,58922L,58923L,58924L,58925L,58926L,58927L,
8980058928L,58929L,58930L,58931L,58932L,58933L,58934L,58935L,58936L,58937L,
8980158938L,58939L,58940L,58941L,58942L,58943L,58944L,58945L,58946L,58947L,
8980258948L,58949L,58950L,58951L,58952L,58953L,58954L,58955L,58956L,58957L,
8980358958L,58959L,58960L,58961L,58962L,58963L,58964L,58965L,58966L,58967L,
8980458968L,58969L,58970L,58971L,58972L,58973L,58974L,58975L,58976L,58977L,
8980558978L,58979L,58980L,58981L,58982L,58983L,58984L,58985L,58986L,58987L,
8980658988L,58989L,58990L,58991L,58992L,58993L,58994L,58995L,58996L,58997L,
8980758998L,58999L,59000L,59001L,59002L,59003L,59004L,59005L,59006L,59007L,
8980859008L,59009L,59010L,59011L,59012L,59013L,59014L,59015L,59016L,59017L,
8980959018L,59019L,59020L,59021L,59022L,59023L,59024L,59025L,59026L,59027L,
8981059028L,59029L,59030L,59031L,59032L,59033L,59034L,59035L,59036L,59037L,
8981159038L,59039L,59040L,59041L,59042L,59043L,59044L,59045L,59046L,59047L,
8981259048L,59049L,59050L,59051L,59052L,59053L,59054L,59055L,59056L,59057L,
8981359058L,59059L,59060L,59061L,59062L,59063L,59064L,59065L,59066L,59067L,
8981459068L,59069L,59070L,59071L,59072L,59073L,59074L,59075L,59076L,59077L,
8981559078L,59079L,59080L,59081L,59082L,59083L,59084L,59085L,59086L,59087L,
8981659088L,59089L,59090L,59091L,59092L,59093L,59094L,59095L,59096L,59097L,
8981759098L,59099L,59100L,59101L,59102L,59103L,59104L,59105L,59106L,59107L,
8981859108L,59109L,59110L,59111L,59112L,59113L,59114L,59115L,59116L,59117L,
8981959118L,59119L,59120L,59121L,59122L,59123L,59124L,59125L,59126L,59127L,
8982059128L,59129L,59130L,59131L,59132L,59133L,59134L,59135L,59136L,59137L,
8982159138L,59139L,59140L,59141L,59142L,59143L,59144L,59145L,59146L,59147L,
8982259148L,59149L,59150L,59151L,59152L,59153L,59154L,59155L,59156L,59157L,
8982359158L,59159L,59160L,59161L,59162L,59163L,59164L,59165L,59166L,59167L,
8982459168L,59169L,59170L,59171L,59172L,59173L,59174L,59175L,59176L,59177L,
8982559178L,59179L,59180L,59181L,59182L,59183L,59184L,59185L,59186L,59187L,
8982659188L,59189L,59190L,59191L,59192L,59193L,59194L,59195L,59196L,59197L,
8982759198L,59199L,59200L,59201L,59202L,59203L,59204L,59205L,59206L,59207L,
8982859208L,59209L,59210L,59211L,59212L,59213L,59214L,59215L,59216L,59217L,
8982959218L,59219L,59220L,59221L,59222L,59223L,59224L,59225L,59226L,59227L,
8983059228L,59229L,59230L,59231L,59232L,59233L,59234L,59235L,59236L,59237L,
8983159238L,59239L,59240L,59241L,59242L,59243L,59244L,59245L,59246L,59247L,
8983259248L,59249L,59250L,59251L,59252L,59253L,59254L,59255L,59256L,59257L,
8983359258L,59259L,59260L,59261L,59262L,59263L,59264L,59265L,59266L,59267L,
8983459268L,59269L,59270L,59271L,59272L,59273L,59274L,59275L,59276L,59277L,
8983559278L,59279L,59280L,59281L,59282L,59283L,59284L,59285L,59286L,59287L,
8983659288L,59289L,59290L,59291L,59292L,59293L,59294L,59295L,59296L,59297L,
8983759298L,59299L,59300L,59301L,59302L,59303L,59304L,59305L,59306L,59307L,
8983859308L,59309L,59310L,59311L,59312L,59313L,59314L,59315L,59316L,59317L,
8983959318L,59319L,59320L,59321L,59322L,59323L,59324L,59325L,59326L,59327L,
8984059328L,59329L,59330L,59331L,59332L,59333L,59334L,59335L,59336L,59337L,
8984159338L,59339L,59340L,59341L,59342L,59343L,59344L,59345L,59346L,59347L,
8984259348L,59349L,59350L,59351L,59352L,59353L,59354L,59355L,59356L,59357L,
8984359358L,59359L,59360L,59361L,59362L,59363L,59364L,59365L,59366L,59367L,
8984459368L,59369L,59370L,59371L,59372L,59373L,59374L,59375L,59376L,59377L,
8984559378L,59379L,59380L,59381L,59382L,59383L,59384L,59385L,59386L,59387L,
8984659388L,59389L,59390L,59391L,59392L,59393L,59394L,59395L,59396L,59397L,
8984759398L,59399L,59400L,59401L,59402L,59403L,59404L,59405L,59406L,59407L,
8984859408L,59409L,59410L,59411L,59412L,59413L,59414L,59415L,59416L,59417L,
8984959418L,59419L,59420L,59421L,59422L,59423L,59424L,59425L,59426L,59427L,
8985059428L,59429L,59430L,59431L,59432L,59433L,59434L,59435L,59436L,59437L,
8985159438L,59439L,59440L,59441L,59442L,59443L,59444L,59445L,59446L,59447L,
8985259448L,59449L,59450L,59451L,59452L,59453L,59454L,59455L,59456L,59457L,
8985359458L,59459L,59460L,59461L,59462L,59463L,59464L,59465L,59466L,59467L,
8985459468L,59469L,59470L,59471L,59472L,59473L,59474L,59475L,59476L,59477L,
8985559478L,59479L,59480L,59481L,59482L,59483L,59484L,59485L,59486L,59487L,
8985659488L,59489L,59490L,59491L,59492L,59493L,59494L,59495L,59496L,59497L,
8985759498L,59499L,59500L,59501L,59502L,59503L,59504L,59505L,59506L,59507L,
8985859508L,59509L,59510L,59511L,59512L,59513L,59514L,59515L,59516L,59517L,
8985959518L,59519L,59520L,59521L,59522L,59523L,59524L,59525L,59526L,59527L,
8986059528L,59529L,59530L,59531L,59532L,59533L,59534L,59535L,59536L,59537L,
8986159538L,59539L,59540L,59541L,59542L,59543L,59544L,59545L,59546L,59547L,
8986259548L,59549L,59550L,59551L,59552L,59553L,59554L,59555L,59556L,59557L,
8986359558L,59559L,59560L,59561L,59562L,59563L,59564L,59565L,59566L,59567L,
8986459568L,59569L,59570L,59571L,59572L,59573L,59574L,59575L,59576L,59577L,
8986559578L,59579L,59580L,59581L,59582L,59583L,59584L,59585L,59586L,59587L,
8986659588L,59589L,59590L,59591L,59592L,59593L,59594L,59595L,59596L,59597L,
8986759598L,59599L,59600L,59601L,59602L,59603L,59604L,59605L,59606L,59607L,
8986859608L,59609L,59610L,59611L,59612L,59613L,59614L,59615L,59616L,59617L,
8986959618L,59619L,59620L,59621L,59622L,59623L,59624L,59625L,59626L,59627L,
8987059628L,59629L,59630L,59631L,59632L,59633L,59634L,59635L,59636L,59637L,
8987159638L,59639L,59640L,59641L,59642L,59643L,59644L,59645L,59646L,59647L,
8987259648L,59649L,59650L,59651L,59652L,59653L,59654L,59655L,59656L,59657L,
8987359658L,59659L,59660L,59661L,59662L,59663L,59664L,59665L,59666L,59667L,
8987459668L,59669L,59670L,59671L,59672L,59673L,59674L,59675L,59676L,59677L,
8987559678L,59679L,59680L,59681L,59682L,59683L,59684L,59685L,59686L,59687L,
8987659688L,59689L,59690L,59691L,59692L,59693L,59694L,59695L,59696L,59697L,
8987759698L,59699L,59700L,59701L,59702L,59703L,59704L,59705L,59706L,59707L,
8987859708L,59709L,59710L,59711L,59712L,59713L,59714L,59715L,59716L,59717L,
8987959718L,59719L,59720L,59721L,59722L,59723L,59724L,59725L,59726L,59727L,
8988059728L,59729L,59730L,59731L,59732L,59733L,59734L,59735L,59736L,59737L,
8988159738L,59739L,59740L,59741L,59742L,59743L,59744L,59745L,59746L,59747L,
8988259748L,59749L,59750L,59751L,59752L,59753L,59754L,59755L,59756L,59757L,
8988359758L,59759L,59760L,59761L,59762L,59763L,59764L,59765L,59766L,59767L,
8988459768L,59769L,59770L,59771L,59772L,59773L,59774L,59775L,59776L,59777L,
8988559778L,59779L,59780L,59781L,59782L,59783L,59784L,59785L,59786L,59787L,
8988659788L,59789L,59790L,59791L,59792L,59793L,59794L,59795L,59796L,59797L,
8988759798L,59799L,59800L,59801L,59802L,59803L,59804L,59805L,59806L,59807L,
8988859808L,59809L,59810L,59811L,59812L,59813L,59814L,59815L,59816L,59817L,
8988959818L,59819L,59820L,59821L,59822L,59823L,59824L,59825L,59826L,59827L,
8989059828L,59829L,59830L,59831L,59832L,59833L,59834L,59835L,59836L,59837L,
8989159838L,59839L,59840L,59841L,59842L,59843L,59844L,59845L,59846L,59847L,
8989259848L,59849L,59850L,59851L,59852L,59853L,59854L,59855L,59856L,59857L,
8989359858L,59859L,59860L,59861L,59862L,59863L,59864L,59865L,59866L,59867L,
8989459868L,59869L,59870L,59871L,59872L,59873L,59874L,59875L,59876L,59877L,
8989559878L,59879L,59880L,59881L,59882L,59883L,59884L,59885L,59886L,59887L,
8989659888L,59889L,59890L,59891L,59892L,59893L,59894L,59895L,59896L,59897L,
8989759898L,59899L,59900L,59901L,59902L,59903L,59904L,59905L,59906L,59907L,
8989859908L,59909L,59910L,59911L,59912L,59913L,59914L,59915L,59916L,59917L,
8989959918L,59919L,59920L,59921L,59922L,59923L,59924L,59925L,59926L,59927L,
8990059928L,59929L,59930L,59931L,59932L,59933L,59934L,59935L,59936L,59937L,
8990159938L,59939L,59940L,59941L,59942L,59943L,59944L,59945L,59946L,59947L,
8990259948L,59949L,59950L,59951L,59952L,59953L,59954L,59955L,59956L,59957L,
8990359958L,59959L,59960L,59961L,59962L,59963L,59964L,59965L,59966L,59967L,
8990459968L,59969L,59970L,59971L,59972L,59973L,59974L,59975L,59976L,59977L,
8990559978L,59979L,59980L,59981L,59982L,59983L,59984L,59985L,59986L,59987L,
8990659988L,59989L,59990L,59991L,59992L,59993L,59994L,59995L,59996L,59997L,
8990759998L,59999L,60000L,60001L,60002L,60003L,60004L,60005L,60006L,60007L,
8990860008L,60009L,60010L,60011L,60012L,60013L,60014L,60015L,60016L,60017L,
8990960018L,60019L,60020L,60021L,60022L,60023L,60024L,60025L,60026L,60027L,
8991060028L,60029L,60030L,60031L,60032L,60033L,60034L,60035L,60036L,60037L,
8991160038L,60039L,60040L,60041L,60042L,60043L,60044L,60045L,60046L,60047L,
8991260048L,60049L,60050L,60051L,60052L,60053L,60054L,60055L,60056L,60057L,
8991360058L,60059L,60060L,60061L,60062L,60063L,60064L,60065L,60066L,60067L,
8991460068L,60069L,60070L,60071L,60072L,60073L,60074L,60075L,60076L,60077L,
8991560078L,60079L,60080L,60081L,60082L,60083L,60084L,60085L,60086L,60087L,
8991660088L,60089L,60090L,60091L,60092L,60093L,60094L,60095L,60096L,60097L,
8991760098L,60099L,60100L,60101L,60102L,60103L,60104L,60105L,60106L,60107L,
8991860108L,60109L,60110L,60111L,60112L,60113L,60114L,60115L,60116L,60117L,
8991960118L,60119L,60120L,60121L,60122L,60123L,60124L,60125L,60126L,60127L,
8992060128L,60129L,60130L,60131L,60132L,60133L,60134L,60135L,60136L,60137L,
8992160138L,60139L,60140L,60141L,60142L,60143L,60144L,60145L,60146L,60147L,
8992260148L,60149L,60150L,60151L,60152L,60153L,60154L,60155L,60156L,60157L,
8992360158L,60159L,60160L,60161L,60162L,60163L,60164L,60165L,60166L,60167L,
8992460168L,60169L,60170L,60171L,60172L,60173L,60174L,60175L,60176L,60177L,
8992560178L,60179L,60180L,60181L,60182L,60183L,60184L,60185L,60186L,60187L,
8992660188L,60189L,60190L,60191L,60192L,60193L,60194L,60195L,60196L,60197L,
8992760198L,60199L,60200L,60201L,60202L,60203L,60204L,60205L,60206L,60207L,
8992860208L,60209L,60210L,60211L,60212L,60213L,60214L,60215L,60216L,60217L,
8992960218L,60219L,60220L,60221L,60222L,60223L,60224L,60225L,60226L,60227L,
8993060228L,60229L,60230L,60231L,60232L,60233L,60234L,60235L,60236L,60237L,
8993160238L,60239L,60240L,60241L,60242L,60243L,60244L,60245L,60246L,60247L,
8993260248L,60249L,60250L,60251L,60252L,60253L,60254L,60255L,60256L,60257L,
8993360258L,60259L,60260L,60261L,60262L,60263L,60264L,60265L,60266L,60267L,
8993460268L,60269L,60270L,60271L,60272L,60273L,60274L,60275L,60276L,60277L,
8993560278L,60279L,60280L,60281L,60282L,60283L,60284L,60285L,60286L,60287L,
8993660288L,60289L,60290L,60291L,60292L,60293L,60294L,60295L,60296L,60297L,
8993760298L,60299L,60300L,60301L,60302L,60303L,60304L,60305L,60306L,60307L,
8993860308L,60309L,60310L,60311L,60312L,60313L,60314L,60315L,60316L,60317L,
8993960318L,60319L,60320L,60321L,60322L,60323L,60324L,60325L,60326L,60327L,
8994060328L,60329L,60330L,60331L,60332L,60333L,60334L,60335L,60336L,60337L,
8994160338L,60339L,60340L,60341L,60342L,60343L,60344L,60345L,60346L,60347L,
8994260348L,60349L,60350L,60351L,60352L,60353L,60354L,60355L,60356L,60357L,
8994360358L,60359L,60360L,60361L,60362L,60363L,60364L,60365L,60366L,60367L,
8994460368L,60369L,60370L,60371L,60372L,60373L,60374L,60375L,60376L,60377L,
8994560378L,60379L,60380L,60381L,60382L,60383L,60384L,60385L,60386L,60387L,
8994660388L,60389L,60390L,60391L,60392L,60393L,60394L,60395L,60396L,60397L,
8994760398L,60399L,60400L,60401L,60402L,60403L,60404L,60405L,60406L,60407L,
8994860408L,60409L,60410L,60411L,60412L,60413L,60414L,60415L,60416L,60417L,
8994960418L,60419L,60420L,60421L,60422L,60423L,60424L,60425L,60426L,60427L,
8995060428L,60429L,60430L,60431L,60432L,60433L,60434L,60435L,60436L,60437L,
8995160438L,60439L,60440L,60441L,60442L,60443L,60444L,60445L,60446L,60447L,
8995260448L,60449L,60450L,60451L,60452L,60453L,60454L,60455L,60456L,60457L,
8995360458L,60459L,60460L,60461L,60462L,60463L,60464L,60465L,60466L,60467L,
8995460468L,60469L,60470L,60471L,60472L,60473L,60474L,60475L,60476L,60477L,
8995560478L,60479L,60480L,60481L,60482L,60483L,60484L,60485L,60486L,60487L,
8995660488L,60489L,60490L,60491L,60492L,60493L,60494L,60495L,60496L,60497L,
8995760498L,60499L,60500L,60501L,60502L,60503L,60504L,60505L,60506L,60507L,
8995860508L,60509L,60510L,60511L,60512L,60513L,60514L,60515L,60516L,60517L,
8995960518L,60519L,60520L,60521L,60522L,60523L,60524L,60525L,60526L,60527L,
8996060528L,60529L,60530L,60531L,60532L,60533L,60534L,60535L,60536L,60537L,
8996160538L,60539L,60540L,60541L,60542L,60543L,60544L,60545L,60546L,60547L,
8996260548L,60549L,60550L,60551L,60552L,60553L,60554L,60555L,60556L,60557L,
8996360558L,60559L,60560L,60561L,60562L,60563L,60564L,60565L,60566L,60567L,
8996460568L,60569L,60570L,60571L,60572L,60573L,60574L,60575L,60576L,60577L,
8996560578L,60579L,60580L,60581L,60582L,60583L,60584L,60585L,60586L,60587L,
8996660588L,60589L,60590L,60591L,60592L,60593L,60594L,60595L,60596L,60597L,
8996760598L,60599L,60600L,60601L,60602L,60603L,60604L,60605L,60606L,60607L,
8996860608L,60609L,60610L,60611L,60612L,60613L,60614L,60615L,60616L,60617L,
8996960618L,60619L,60620L,60621L,60622L,60623L,60624L,60625L,60626L,60627L,
8997060628L,60629L,60630L,60631L,60632L,60633L,60634L,60635L,60636L,60637L,
8997160638L,60639L,60640L,60641L,60642L,60643L,60644L,60645L,60646L,60647L,
8997260648L,60649L,60650L,60651L,60652L,60653L,60654L,60655L,60656L,60657L,
8997360658L,60659L,60660L,60661L,60662L,60663L,60664L,60665L,60666L,60667L,
8997460668L,60669L,60670L,60671L,60672L,60673L,60674L,60675L,60676L,60677L,
8997560678L,60679L,60680L,60681L,60682L,60683L,60684L,60685L,60686L,60687L,
8997660688L,60689L,60690L,60691L,60692L,60693L,60694L,60695L,60696L,60697L,
8997760698L,60699L,60700L,60701L,60702L,60703L,60704L,60705L,60706L,60707L,
8997860708L,60709L,60710L,60711L,60712L,60713L,60714L,60715L,60716L,60717L,
8997960718L,60719L,60720L,60721L,60722L,60723L,60724L,60725L,60726L,60727L,
8998060728L,60729L,60730L,60731L,60732L,60733L,60734L,60735L,60736L,60737L,
8998160738L,60739L,60740L,60741L,60742L,60743L,60744L,60745L,60746L,60747L,
8998260748L,60749L,60750L,60751L,60752L,60753L,60754L,60755L,60756L,60757L,
8998360758L,60759L,60760L,60761L,60762L,60763L,60764L,60765L,60766L,60767L,
8998460768L,60769L,60770L,60771L,60772L,60773L,60774L,60775L,60776L,60777L,
8998560778L,60779L,60780L,60781L,60782L,60783L,60784L,60785L,60786L,60787L,
8998660788L,60789L,60790L,60791L,60792L,60793L,60794L,60795L,60796L,60797L,
8998760798L,60799L,60800L,60801L,60802L,60803L,60804L,60805L,60806L,60807L,
8998860808L,60809L,60810L,60811L,60812L,60813L,60814L,60815L,60816L,60817L,
8998960818L,60819L,60820L,60821L,60822L,60823L,60824L,60825L,60826L,60827L,
8999060828L,60829L,60830L,60831L,60832L,60833L,60834L,60835L,60836L,60837L,
8999160838L,60839L,60840L,60841L,60842L,60843L,60844L,60845L,60846L,60847L,
8999260848L,60849L,60850L,60851L,60852L,60853L,60854L,60855L,60856L,60857L,
8999360858L,60859L,60860L,60861L,60862L,60863L,60864L,60865L,60866L,60867L,
8999460868L,60869L,60870L,60871L,60872L,60873L,60874L,60875L,60876L,60877L,
8999560878L,60879L,60880L,60881L,60882L,60883L,60884L,60885L,60886L,60887L,
8999660888L,60889L,60890L,60891L,60892L,60893L,60894L,60895L,60896L,60897L,
8999760898L,60899L,60900L,60901L,60902L,60903L,60904L,60905L,60906L,60907L,
8999860908L,60909L,60910L,60911L,60912L,60913L,60914L,60915L,60916L,60917L,
8999960918L,60919L,60920L,60921L,60922L,60923L,60924L,60925L,60926L,60927L,
9000060928L,60929L,60930L,60931L,60932L,60933L,60934L,60935L,60936L,60937L,
9000160938L,60939L,60940L,60941L,60942L,60943L,60944L,60945L,60946L,60947L,
9000260948L,60949L,60950L,60951L,60952L,60953L,60954L,60955L,60956L,60957L,
9000360958L,60959L,60960L,60961L,60962L,60963L,60964L,60965L,60966L,60967L,
9000460968L,60969L,60970L,60971L,60972L,60973L,60974L,60975L,60976L,60977L,
9000560978L,60979L,60980L,60981L,60982L,60983L,60984L,60985L,60986L,60987L,
9000660988L,60989L,60990L,60991L,60992L,60993L,60994L,60995L,60996L,60997L,
9000760998L,60999L,61000L,61001L,61002L,61003L,61004L,61005L,61006L,61007L,
9000861008L,61009L,61010L,61011L,61012L,61013L,61014L,61015L,61016L,61017L,
9000961018L,61019L,61020L,61021L,61022L,61023L,61024L,61025L,61026L,61027L,
9001061028L,61029L,61030L,61031L,61032L,61033L,61034L,61035L,61036L,61037L,
9001161038L,61039L,61040L,61041L,61042L,61043L,61044L,61045L,61046L,61047L,
9001261048L,61049L,61050L,61051L,61052L,61053L,61054L,61055L,61056L,61057L,
9001361058L,61059L,61060L,61061L,61062L,61063L,61064L,61065L,61066L,61067L,
9001461068L,61069L,61070L,61071L,61072L,61073L,61074L,61075L,61076L,61077L,
9001561078L,61079L,61080L,61081L,61082L,61083L,61084L,61085L,61086L,61087L,
9001661088L,61089L,61090L,61091L,61092L,61093L,61094L,61095L,61096L,61097L,
9001761098L,61099L,61100L,61101L,61102L,61103L,61104L,61105L,61106L,61107L,
9001861108L,61109L,61110L,61111L,61112L,61113L,61114L,61115L,61116L,61117L,
9001961118L,61119L,61120L,61121L,61122L,61123L,61124L,61125L,61126L,61127L,
9002061128L,61129L,61130L,61131L,61132L,61133L,61134L,61135L,61136L,61137L,
9002161138L,61139L,61140L,61141L,61142L,61143L,61144L,61145L,61146L,61147L,
9002261148L,61149L,61150L,61151L,61152L,61153L,61154L,61155L,61156L,61157L,
9002361158L,61159L,61160L,61161L,61162L,61163L,61164L,61165L,61166L,61167L,
9002461168L,61169L,61170L,61171L,61172L,61173L,61174L,61175L,61176L,61177L,
9002561178L,61179L,61180L,61181L,61182L,61183L,61184L,61185L,61186L,61187L,
9002661188L,61189L,61190L,61191L,61192L,61193L,61194L,61195L,61196L,61197L,
9002761198L,61199L,61200L,61201L,61202L,61203L,61204L,61205L,61206L,61207L,
9002861208L,61209L,61210L,61211L,61212L,61213L,61214L,61215L,61216L,61217L,
9002961218L,61219L,61220L,61221L,61222L,61223L,61224L,61225L,61226L,61227L,
9003061228L,61229L,61230L,61231L,61232L,61233L,61234L,61235L,61236L,61237L,
9003161238L,61239L,61240L,61241L,61242L,61243L,61244L,61245L,61246L,61247L,
9003261248L,61249L,61250L,61251L,61252L,61253L,61254L,61255L,61256L,61257L,
9003361258L,61259L,61260L,61261L,61262L,61263L,61264L,61265L,61266L,61267L,
9003461268L,61269L,61270L,61271L,61272L,61273L,61274L,61275L,61276L,61277L,
9003561278L,61279L,61280L,61281L,61282L,61283L,61284L,61285L,61286L,61287L,
9003661288L,61289L,61290L,61291L,61292L,61293L,61294L,61295L,61296L,61297L,
9003761298L,61299L,61300L,61301L,61302L,61303L,61304L,61305L,61306L,61307L,
9003861308L,61309L,61310L,61311L,61312L,61313L,61314L,61315L,61316L,61317L,
9003961318L,61319L,61320L,61321L,61322L,61323L,61324L,61325L,61326L,61327L,
9004061328L,61329L,61330L,61331L,61332L,61333L,61334L,61335L,61336L,61337L,
9004161338L,61339L,61340L,61341L,61342L,61343L,61344L,61345L,61346L,61347L,
9004261348L,61349L,61350L,61351L,61352L,61353L,61354L,61355L,61356L,61357L,
9004361358L,61359L,61360L,61361L,61362L,61363L,61364L,61365L,61366L,61367L,
9004461368L,61369L,61370L,61371L,61372L,61373L,61374L,61375L,61376L,61377L,
9004561378L,61379L,61380L,61381L,61382L,61383L,61384L,61385L,61386L,61387L,
9004661388L,61389L,61390L,61391L,61392L,61393L,61394L,61395L,61396L,61397L,
9004761398L,61399L,61400L,61401L,61402L,61403L,61404L,61405L,61406L,61407L,
9004861408L,61409L,61410L,61411L,61412L,61413L,61414L,61415L,61416L,61417L,
9004961418L,61419L,61420L,61421L,61422L,61423L,61424L,61425L,61426L,61427L,
9005061428L,61429L,61430L,61431L,61432L,61433L,61434L,61435L,61436L,61437L,
9005161438L,61439L,61440L,61441L,61442L,61443L,61444L,61445L,61446L,61447L,
9005261448L,61449L,61450L,61451L,61452L,61453L,61454L,61455L,61456L,61457L,
9005361458L,61459L,61460L,61461L,61462L,61463L,61464L,61465L,61466L,61467L,
9005461468L,61469L,61470L,61471L,61472L,61473L,61474L,61475L,61476L,61477L,
9005561478L,61479L,61480L,61481L,61482L,61483L,61484L,61485L,61486L,61487L,
9005661488L,61489L,61490L,61491L,61492L,61493L,61494L,61495L,61496L,61497L,
9005761498L,61499L,61500L,61501L,61502L,61503L,61504L,61505L,61506L,61507L,
9005861508L,61509L,61510L,61511L,61512L,61513L,61514L,61515L,61516L,61517L,
9005961518L,61519L,61520L,61521L,61522L,61523L,61524L,61525L,61526L,61527L,
9006061528L,61529L,61530L,61531L,61532L,61533L,61534L,61535L,61536L,61537L,
9006161538L,61539L,61540L,61541L,61542L,61543L,61544L,61545L,61546L,61547L,
9006261548L,61549L,61550L,61551L,61552L,61553L,61554L,61555L,61556L,61557L,
9006361558L,61559L,61560L,61561L,61562L,61563L,61564L,61565L,61566L,61567L,
9006461568L,61569L,61570L,61571L,61572L,61573L,61574L,61575L,61576L,61577L,
9006561578L,61579L,61580L,61581L,61582L,61583L,61584L,61585L,61586L,61587L,
9006661588L,61589L,61590L,61591L,61592L,61593L,61594L,61595L,61596L,61597L,
9006761598L,61599L,61600L,61601L,61602L,61603L,61604L,61605L,61606L,61607L,
9006861608L,61609L,61610L,61611L,61612L,61613L,61614L,61615L,61616L,61617L,
9006961618L,61619L,61620L,61621L,61622L,61623L,61624L,61625L,61626L,61627L,
9007061628L,61629L,61630L,61631L,61632L,61633L,61634L,61635L,61636L,61637L,
9007161638L,61639L,61640L,61641L,61642L,61643L,61644L,61645L,61646L,61647L,
9007261648L,61649L,61650L,61651L,61652L,61653L,61654L,61655L,61656L,61657L,
9007361658L,61659L,61660L,61661L,61662L,61663L,61664L,61665L,61666L,61667L,
9007461668L,61669L,61670L,61671L,61672L,61673L,61674L,61675L,61676L,61677L,
9007561678L,61679L,61680L,61681L,61682L,61683L,61684L,61685L,61686L,61687L,
9007661688L,61689L,61690L,61691L,61692L,61693L,61694L,61695L,61696L,61697L,
9007761698L,61699L,61700L,61701L,61702L,61703L,61704L,61705L,61706L,61707L,
9007861708L,61709L,61710L,61711L,61712L,61713L,61714L,61715L,61716L,61717L,
9007961718L,61719L,61720L,61721L,61722L,61723L,61724L,61725L,61726L,61727L,
9008061728L,61729L,61730L,61731L,61732L,61733L,61734L,61735L,61736L,61737L,
9008161738L,61739L,61740L,61741L,61742L,61743L,61744L,61745L,61746L,61747L,
9008261748L,61749L,61750L,61751L,61752L,61753L,61754L,61755L,61756L,61757L,
9008361758L,61759L,61760L,61761L,61762L,61763L,61764L,61765L,61766L,61767L,
9008461768L,61769L,61770L,61771L,61772L,61773L,61774L,61775L,61776L,61777L,
9008561778L,61779L,61780L,61781L,61782L,61783L,61784L,61785L,61786L,61787L,
9008661788L,61789L,61790L,61791L,61792L,61793L,61794L,61795L,61796L,61797L,
9008761798L,61799L,61800L,61801L,61802L,61803L,61804L,61805L,61806L,61807L,
9008861808L,61809L,61810L,61811L,61812L,61813L,61814L,61815L,61816L,61817L,
9008961818L,61819L,61820L,61821L,61822L,61823L,61824L,61825L,61826L,61827L,
9009061828L,61829L,61830L,61831L,61832L,61833L,61834L,61835L,61836L,61837L,
9009161838L,61839L,61840L,61841L,61842L,61843L,61844L,61845L,61846L,61847L,
9009261848L,61849L,61850L,61851L,61852L,61853L,61854L,61855L,61856L,61857L,
9009361858L,61859L,61860L,61861L,61862L,61863L,61864L,61865L,61866L,61867L,
9009461868L,61869L,61870L,61871L,61872L,61873L,61874L,61875L,61876L,61877L,
9009561878L,61879L,61880L,61881L,61882L,61883L,61884L,61885L,61886L,61887L,
9009661888L,61889L,61890L,61891L,61892L,61893L,61894L,61895L,61896L,61897L,
9009761898L,61899L,61900L,61901L,61902L,61903L,61904L,61905L,61906L,61907L,
9009861908L,61909L,61910L,61911L,61912L,61913L,61914L,61915L,61916L,61917L,
9009961918L,61919L,61920L,61921L,61922L,61923L,61924L,61925L,61926L,61927L,
9010061928L,61929L,61930L,61931L,61932L,61933L,61934L,61935L,61936L,61937L,
9010161938L,61939L,61940L,61941L,61942L,61943L,61944L,61945L,61946L,61947L,
9010261948L,61949L,61950L,61951L,61952L,61953L,61954L,61955L,61956L,61957L,
9010361958L,61959L,61960L,61961L,61962L,61963L,61964L,61965L,61966L,61967L,
9010461968L,61969L,61970L,61971L,61972L,61973L,61974L,61975L,61976L,61977L,
9010561978L,61979L,61980L,61981L,61982L,61983L,61984L,61985L,61986L,61987L,
9010661988L,61989L,61990L,61991L,61992L,61993L,61994L,61995L,61996L,61997L,
9010761998L,61999L,62000L,62001L,62002L,62003L,62004L,62005L,62006L,62007L,
9010862008L,62009L,62010L,62011L,62012L,62013L,62014L,62015L,62016L,62017L,
9010962018L,62019L,62020L,62021L,62022L,62023L,62024L,62025L,62026L,62027L,
9011062028L,62029L,62030L,62031L,62032L,62033L,62034L,62035L,62036L,62037L,
9011162038L,62039L,62040L,62041L,62042L,62043L,62044L,62045L,62046L,62047L,
9011262048L,62049L,62050L,62051L,62052L,62053L,62054L,62055L,62056L,62057L,
9011362058L,62059L,62060L,62061L,62062L,62063L,62064L,62065L,62066L,62067L,
9011462068L,62069L,62070L,62071L,62072L,62073L,62074L,62075L,62076L,62077L,
9011562078L,62079L,62080L,62081L,62082L,62083L,62084L,62085L,62086L,62087L,
9011662088L,62089L,62090L,62091L,62092L,62093L,62094L,62095L,62096L,62097L,
9011762098L,62099L,62100L,62101L,62102L,62103L,62104L,62105L,62106L,62107L,
9011862108L,62109L,62110L,62111L,62112L,62113L,62114L,62115L,62116L,62117L,
9011962118L,62119L,62120L,62121L,62122L,62123L,62124L,62125L,62126L,62127L,
9012062128L,62129L,62130L,62131L,62132L,62133L,62134L,62135L,62136L,62137L,
9012162138L,62139L,62140L,62141L,62142L,62143L,62144L,62145L,62146L,62147L,
9012262148L,62149L,62150L,62151L,62152L,62153L,62154L,62155L,62156L,62157L,
9012362158L,62159L,62160L,62161L,62162L,62163L,62164L,62165L,62166L,62167L,
9012462168L,62169L,62170L,62171L,62172L,62173L,62174L,62175L,62176L,62177L,
9012562178L,62179L,62180L,62181L,62182L,62183L,62184L,62185L,62186L,62187L,
9012662188L,62189L,62190L,62191L,62192L,62193L,62194L,62195L,62196L,62197L,
9012762198L,62199L,62200L,62201L,62202L,62203L,62204L,62205L,62206L,62207L,
9012862208L,62209L,62210L,62211L,62212L,62213L,62214L,62215L,62216L,62217L,
9012962218L,62219L,62220L,62221L,62222L,62223L,62224L,62225L,62226L,62227L,
9013062228L,62229L,62230L,62231L,62232L,62233L,62234L,62235L,62236L,62237L,
9013162238L,62239L,62240L,62241L,62242L,62243L,62244L,62245L,62246L,62247L,
9013262248L,62249L,62250L,62251L,62252L,62253L,62254L,62255L,62256L,62257L,
9013362258L,62259L,62260L,62261L,62262L,62263L,62264L,62265L,62266L,62267L,
9013462268L,62269L,62270L,62271L,62272L,62273L,62274L,62275L,62276L,62277L,
9013562278L,62279L,62280L,62281L,62282L,62283L,62284L,62285L,62286L,62287L,
9013662288L,62289L,62290L,62291L,62292L,62293L,62294L,62295L,62296L,62297L,
9013762298L,62299L,62300L,62301L,62302L,62303L,62304L,62305L,62306L,62307L,
9013862308L,62309L,62310L,62311L,62312L,62313L,62314L,62315L,62316L,62317L,
9013962318L,62319L,62320L,62321L,62322L,62323L,62324L,62325L,62326L,62327L,
9014062328L,62329L,62330L,62331L,62332L,62333L,62334L,62335L,62336L,62337L,
9014162338L,62339L,62340L,62341L,62342L,62343L,62344L,62345L,62346L,62347L,
9014262348L,62349L,62350L,62351L,62352L,62353L,62354L,62355L,62356L,62357L,
9014362358L,62359L,62360L,62361L,62362L,62363L,62364L,62365L,62366L,62367L,
9014462368L,62369L,62370L,62371L,62372L,62373L,62374L,62375L,62376L,62377L,
9014562378L,62379L,62380L,62381L,62382L,62383L,62384L,62385L,62386L,62387L,
9014662388L,62389L,62390L,62391L,62392L,62393L,62394L,62395L,62396L,62397L,
9014762398L,62399L,62400L,62401L,62402L,62403L,62404L,62405L,62406L,62407L,
9014862408L,62409L,62410L,62411L,62412L,62413L,62414L,62415L,62416L,62417L,
9014962418L,62419L,62420L,62421L,62422L,62423L,62424L,62425L,62426L,62427L,
9015062428L,62429L,62430L,62431L,62432L,62433L,62434L,62435L,62436L,62437L,
9015162438L,62439L,62440L,62441L,62442L,62443L,62444L,62445L,62446L,62447L,
9015262448L,62449L,62450L,62451L,62452L,62453L,62454L,62455L,62456L,62457L,
9015362458L,62459L,62460L,62461L,62462L,62463L,62464L,62465L,62466L,62467L,
9015462468L,62469L,62470L,62471L,62472L,62473L,62474L,62475L,62476L,62477L,
9015562478L,62479L,62480L,62481L,62482L,62483L,62484L,62485L,62486L,62487L,
9015662488L,62489L,62490L,62491L,62492L,62493L,62494L,62495L,62496L,62497L,
9015762498L,62499L,62500L,62501L,62502L,62503L,62504L,62505L,62506L,62507L,
9015862508L,62509L,62510L,62511L,62512L,62513L,62514L,62515L,62516L,62517L,
9015962518L,62519L,62520L,62521L,62522L,62523L,62524L,62525L,62526L,62527L,
9016062528L,62529L,62530L,62531L,62532L,62533L,62534L,62535L,62536L,62537L,
9016162538L,62539L,62540L,62541L,62542L,62543L,62544L,62545L,62546L,62547L,
9016262548L,62549L,62550L,62551L,62552L,62553L,62554L,62555L,62556L,62557L,
9016362558L,62559L,62560L,62561L,62562L,62563L,62564L,62565L,62566L,62567L,
9016462568L,62569L,62570L,62571L,62572L,62573L,62574L,62575L,62576L,62577L,
9016562578L,62579L,62580L,62581L,62582L,62583L,62584L,62585L,62586L,62587L,
9016662588L,62589L,62590L,62591L,62592L,62593L,62594L,62595L,62596L,62597L,
9016762598L,62599L,62600L,62601L,62602L,62603L,62604L,62605L,62606L,62607L,
9016862608L,62609L,62610L,62611L,62612L,62613L,62614L,62615L,62616L,62617L,
9016962618L,62619L,62620L,62621L,62622L,62623L,62624L,62625L,62626L,62627L,
9017062628L,62629L,62630L,62631L,62632L,62633L,62634L,62635L,62636L,62637L,
9017162638L,62639L,62640L,62641L,62642L,62643L,62644L,62645L,62646L,62647L,
9017262648L,62649L,62650L,62651L,62652L,62653L,62654L,62655L,62656L,62657L,
9017362658L,62659L,62660L,62661L,62662L,62663L,62664L,62665L,62666L,62667L,
9017462668L,62669L,62670L,62671L,62672L,62673L,62674L,62675L,62676L,62677L,
9017562678L,62679L,62680L,62681L,62682L,62683L,62684L,62685L,62686L,62687L,
9017662688L,62689L,62690L,62691L,62692L,62693L,62694L,62695L,62696L,62697L,
9017762698L,62699L,62700L,62701L,62702L,62703L,62704L,62705L,62706L,62707L,
9017862708L,62709L,62710L,62711L,62712L,62713L,62714L,62715L,62716L,62717L,
9017962718L,62719L,62720L,62721L,62722L,62723L,62724L,62725L,62726L,62727L,
9018062728L,62729L,62730L,62731L,62732L,62733L,62734L,62735L,62736L,62737L,
9018162738L,62739L,62740L,62741L,62742L,62743L,62744L,62745L,62746L,62747L,
9018262748L,62749L,62750L,62751L,62752L,62753L,62754L,62755L,62756L,62757L,
9018362758L,62759L,62760L,62761L,62762L,62763L,62764L,62765L,62766L,62767L,
9018462768L,62769L,62770L,62771L,62772L,62773L,62774L,62775L,62776L,62777L,
9018562778L,62779L,62780L,62781L,62782L,62783L,62784L,62785L,62786L,62787L,
9018662788L,62789L,62790L,62791L,62792L,62793L,62794L,62795L,62796L,62797L,
9018762798L,62799L,62800L,62801L,62802L,62803L,62804L,62805L,62806L,62807L,
9018862808L,62809L,62810L,62811L,62812L,62813L,62814L,62815L,62816L,62817L,
9018962818L,62819L,62820L,62821L,62822L,62823L,62824L,62825L,62826L,62827L,
9019062828L,62829L,62830L,62831L,62832L,62833L,62834L,62835L,62836L,62837L,
9019162838L,62839L,62840L,62841L,62842L,62843L,62844L,62845L,62846L,62847L,
9019262848L,62849L,62850L,62851L,62852L,62853L,62854L,62855L,62856L,62857L,
9019362858L,62859L,62860L,62861L,62862L,62863L,62864L,62865L,62866L,62867L,
9019462868L,62869L,62870L,62871L,62872L,62873L,62874L,62875L,62876L,62877L,
9019562878L,62879L,62880L,62881L,62882L,62883L,62884L,62885L,62886L,62887L,
9019662888L,62889L,62890L,62891L,62892L,62893L,62894L,62895L,62896L,62897L,
9019762898L,62899L,62900L,62901L,62902L,62903L,62904L,62905L,62906L,62907L,
9019862908L,62909L,62910L,62911L,62912L,62913L,62914L,62915L,62916L,62917L,
9019962918L,62919L,62920L,62921L,62922L,62923L,62924L,62925L,62926L,62927L,
9020062928L,62929L,62930L,62931L,62932L,62933L,62934L,62935L,62936L,62937L,
9020162938L,62939L,62940L,62941L,62942L,62943L,62944L,62945L,62946L,62947L,
9020262948L,62949L,62950L,62951L,62952L,62953L,62954L,62955L,62956L,62957L,
9020362958L,62959L,62960L,62961L,62962L,62963L,62964L,62965L,62966L,62967L,
9020462968L,62969L,62970L,62971L,62972L,62973L,62974L,62975L,62976L,62977L,
9020562978L,62979L,62980L,62981L,62982L,62983L,62984L,62985L,62986L,62987L,
9020662988L,62989L,62990L,62991L,62992L,62993L,62994L,62995L,62996L,62997L,
9020762998L,62999L,63000L,63001L,63002L,63003L,63004L,63005L,63006L,63007L,
9020863008L,63009L,63010L,63011L,63012L,63013L,63014L,63015L,63016L,63017L,
9020963018L,63019L,63020L,63021L,63022L,63023L,63024L,63025L,63026L,63027L,
9021063028L,63029L,63030L,63031L,63032L,63033L,63034L,63035L,63036L,63037L,
9021163038L,63039L,63040L,63041L,63042L,63043L,63044L,63045L,63046L,63047L,
9021263048L,63049L,63050L,63051L,63052L,63053L,63054L,63055L,63056L,63057L,
9021363058L,63059L,63060L,63061L,63062L,63063L,63064L,63065L,63066L,63067L,
9021463068L,63069L,63070L,63071L,63072L,63073L,63074L,63075L,63076L,63077L,
9021563078L,63079L,63080L,63081L,63082L,63083L,63084L,63085L,63086L,63087L,
9021663088L,63089L,63090L,63091L,63092L,63093L,63094L,63095L,63096L,63097L,
9021763098L,63099L,63100L,63101L,63102L,63103L,63104L,63105L,63106L,63107L,
9021863108L,63109L,63110L,63111L,63112L,63113L,63114L,63115L,63116L,63117L,
9021963118L,63119L,63120L,63121L,63122L,63123L,63124L,63125L,63126L,63127L,
9022063128L,63129L,63130L,63131L,63132L,63133L,63134L,63135L,63136L,63137L,
9022163138L,63139L,63140L,63141L,63142L,63143L,63144L,63145L,63146L,63147L,
9022263148L,63149L,63150L,63151L,63152L,63153L,63154L,63155L,63156L,63157L,
9022363158L,63159L,63160L,63161L,63162L,63163L,63164L,63165L,63166L,63167L,
9022463168L,63169L,63170L,63171L,63172L,63173L,63174L,63175L,63176L,63177L,
9022563178L,63179L,63180L,63181L,63182L,63183L,63184L,63185L,63186L,63187L,
9022663188L,63189L,63190L,63191L,63192L,63193L,63194L,63195L,63196L,63197L,
9022763198L,63199L,63200L,63201L,63202L,63203L,63204L,63205L,63206L,63207L,
9022863208L,63209L,63210L,63211L,63212L,63213L,63214L,63215L,63216L,63217L,
9022963218L,63219L,63220L,63221L,63222L,63223L,63224L,63225L,63226L,63227L,
9023063228L,63229L,63230L,63231L,63232L,63233L,63234L,63235L,63236L,63237L,
9023163238L,63239L,63240L,63241L,63242L,63243L,63244L,63245L,63246L,63247L,
9023263248L,63249L,63250L,63251L,63252L,63253L,63254L,63255L,63256L,63257L,
9023363258L,63259L,63260L,63261L,63262L,63263L,63264L,63265L,63266L,63267L,
9023463268L,63269L,63270L,63271L,63272L,63273L,63274L,63275L,63276L,63277L,
9023563278L,63279L,63280L,63281L,63282L,63283L,63284L,63285L,63286L,63287L,
9023663288L,63289L,63290L,63291L,63292L,63293L,63294L,63295L,63296L,63297L,
9023763298L,63299L,63300L,63301L,63302L,63303L,63304L,63305L,63306L,63307L,
9023863308L,63309L,63310L,63311L,63312L,63313L,63314L,63315L,63316L,63317L,
9023963318L,63319L,63320L,63321L,63322L,63323L,63324L,63325L,63326L,63327L,
9024063328L,63329L,63330L,63331L,63332L,63333L,63334L,63335L,63336L,63337L,
9024163338L,63339L,63340L,63341L,63342L,63343L,63344L,63345L,63346L,63347L,
9024263348L,63349L,63350L,63351L,63352L,63353L,63354L,63355L,63356L,63357L,
9024363358L,63359L,63360L,63361L,63362L,63363L,63364L,63365L,63366L,63367L,
9024463368L,63369L,63370L,63371L,63372L,63373L,63374L,63375L,63376L,63377L,
9024563378L,63379L,63380L,63381L,63382L,63383L,63384L,63385L,63386L,63387L,
9024663388L,63389L,63390L,63391L,63392L,63393L,63394L,63395L,63396L,63397L,
9024763398L,63399L,63400L,63401L,63402L,63403L,63404L,63405L,63406L,63407L,
9024863408L,63409L,63410L,63411L,63412L,63413L,63414L,63415L,63416L,63417L,
9024963418L,63419L,63420L,63421L,63422L,63423L,63424L,63425L,63426L,63427L,
9025063428L,63429L,63430L,63431L,63432L,63433L,63434L,63435L,63436L,63437L,
9025163438L,63439L,63440L,63441L,63442L,63443L,63444L,63445L,63446L,63447L,
9025263448L,63449L,63450L,63451L,63452L,63453L,63454L,63455L,63456L,63457L,
9025363458L,63459L,63460L,63461L,63462L,63463L,63464L,63465L,63466L,63467L,
9025463468L,63469L,63470L,63471L,63472L,63473L,63474L,63475L,63476L,63477L,
9025563478L,63479L,63480L,63481L,63482L,63483L,63484L,63485L,63486L,63487L,
9025663488L,63489L,63490L,63491L,63492L,63493L,63494L,63495L,63496L,63497L,
9025763498L,63499L,63500L,63501L,63502L,63503L,63504L,63505L,63506L,63507L,
9025863508L,63509L,63510L,63511L,63512L,63513L,63514L,63515L,63516L,63517L,
9025963518L,63519L,63520L,63521L,63522L,63523L,63524L,63525L,63526L,63527L,
9026063528L,63529L,63530L,63531L,63532L,63533L,63534L,63535L,63536L,63537L,
9026163538L,63539L,63540L,63541L,63542L,63543L,63544L,63545L,63546L,63547L,
9026263548L,63549L,63550L,63551L,63552L,63553L,63554L,63555L,63556L,63557L,
9026363558L,63559L,63560L,63561L,63562L,63563L,63564L,63565L,63566L,63567L,
9026463568L,63569L,63570L,63571L,63572L,63573L,63574L,63575L,63576L,63577L,
9026563578L,63579L,63580L,63581L,63582L,63583L,63584L,63585L,63586L,63587L,
9026663588L,63589L,63590L,63591L,63592L,63593L,63594L,63595L,63596L,63597L,
9026763598L,63599L,63600L,63601L,63602L,63603L,63604L,63605L,63606L,63607L,
9026863608L,63609L,63610L,63611L,63612L,63613L,63614L,63615L,63616L,63617L,
9026963618L,63619L,63620L,63621L,63622L,63623L,63624L,63625L,63626L,63627L,
9027063628L,63629L,63630L,63631L,63632L,63633L,63634L,63635L,63636L,63637L,
9027163638L,63639L,63640L,63641L,63642L,63643L,63644L,63645L,63646L,63647L,
9027263648L,63649L,63650L,63651L,63652L,63653L,63654L,63655L,63656L,63657L,
9027363658L,63659L,63660L,63661L,63662L,63663L,63664L,63665L,63666L,63667L,
9027463668L,63669L,63670L,63671L,63672L,63673L,63674L,63675L,63676L,63677L,
9027563678L,63679L,63680L,63681L,63682L,63683L,63684L,63685L,63686L,63687L,
9027663688L,63689L,63690L,63691L,63692L,63693L,63694L,63695L,63696L,63697L,
9027763698L,63699L,63700L,63701L,63702L,63703L,63704L,63705L,63706L,63707L,
9027863708L,63709L,63710L,63711L,63712L,63713L,63714L,63715L,63716L,63717L,
9027963718L,63719L,63720L,63721L,63722L,63723L,63724L,63725L,63726L,63727L,
9028063728L,63729L,63730L,63731L,63732L,63733L,63734L,63735L,63736L,63737L,
9028163738L,63739L,63740L,63741L,63742L,63743L,63744L,63745L,63746L,63747L,
9028263748L,63749L,63750L,63751L,63752L,63753L,63754L,63755L,63756L,63757L,
9028363758L,63759L,63760L,63761L,63762L,63763L,63764L,63765L,63766L,63767L,
9028463768L,63769L,63770L,63771L,63772L,63773L,63774L,63775L,63776L,63777L,
9028563778L,63779L,63780L,63781L,63782L,63783L,63784L,63785L,63786L,63787L,
9028663788L,63789L,63790L,63791L,63792L,63793L,63794L,63795L,63796L,63797L,
9028763798L,63799L,63800L,63801L,63802L,63803L,63804L,63805L,63806L,63807L,
9028863808L,63809L,63810L,63811L,63812L,63813L,63814L,63815L,63816L,63817L,
9028963818L,63819L,63820L,63821L,63822L,63823L,63824L,63825L,63826L,63827L,
9029063828L,63829L,63830L,63831L,63832L,63833L,63834L,63835L,63836L,63837L,
9029163838L,63839L,63840L,63841L,63842L,63843L,63844L,63845L,63846L,63847L,
9029263848L,63849L,63850L,63851L,63852L,63853L,63854L,63855L,63856L,63857L,
9029363858L,63859L,63860L,63861L,63862L,63863L,63864L,63865L,63866L,63867L,
9029463868L,63869L,63870L,63871L,63872L,63873L,63874L,63875L,63876L,63877L,
9029563878L,63879L,63880L,63881L,63882L,63883L,63884L,63885L,63886L,63887L,
9029663888L,63889L,63890L,63891L,63892L,63893L,63894L,63895L,63896L,63897L,
9029763898L,63899L,63900L,63901L,63902L,63903L,63904L,63905L,63906L,63907L,
9029863908L,63909L,63910L,63911L,63912L,63913L,63914L,63915L,63916L,63917L,
9029963918L,63919L,63920L,63921L,63922L,63923L,63924L,63925L,63926L,63927L,
9030063928L,63929L,63930L,63931L,63932L,63933L,63934L,63935L,63936L,63937L,
9030163938L,63939L,63940L,63941L,63942L,63943L,63944L,63945L,63946L,63947L,
9030263948L,63949L,63950L,63951L,63952L,63953L,63954L,63955L,63956L,63957L,
9030363958L,63959L,63960L,63961L,63962L,63963L,63964L,63965L,63966L,63967L,
9030463968L,63969L,63970L,63971L,63972L,63973L,63974L,63975L,63976L,63977L,
9030563978L,63979L,63980L,63981L,63982L,63983L,63984L,63985L,63986L,63987L,
9030663988L,63989L,63990L,63991L,63992L,63993L,63994L,63995L,63996L,63997L,
9030763998L,63999L,64000L,64001L,64002L,64003L,64004L,64005L,64006L,64007L,
9030864008L,64009L,64010L,64011L,64012L,64013L,64014L,64015L,64016L,64017L,
9030964018L,64019L,64020L,64021L,64022L,64023L,64024L,64025L,64026L,64027L,
9031064028L,64029L,64030L,64031L,64032L,64033L,64034L,64035L,64036L,64037L,
9031164038L,64039L,64040L,64041L,64042L,64043L,64044L,64045L,64046L,64047L,
9031264048L,64049L,64050L,64051L,64052L,64053L,64054L,64055L,64056L,64057L,
9031364058L,64059L,64060L,64061L,64062L,64063L,64064L,64065L,64066L,64067L,
9031464068L,64069L,64070L,64071L,64072L,64073L,64074L,64075L,64076L,64077L,
9031564078L,64079L,64080L,64081L,64082L,64083L,64084L,64085L,64086L,64087L,
9031664088L,64089L,64090L,64091L,64092L,64093L,64094L,64095L,64096L,64097L,
9031764098L,64099L,64100L,64101L,64102L,64103L,64104L,64105L,64106L,64107L,
9031864108L,64109L,64110L,64111L,64112L,64113L,64114L,64115L,64116L,64117L,
9031964118L,64119L,64120L,64121L,64122L,64123L,64124L,64125L,64126L,64127L,
9032064128L,64129L,64130L,64131L,64132L,64133L,64134L,64135L,64136L,64137L,
9032164138L,64139L,64140L,64141L,64142L,64143L,64144L,64145L,64146L,64147L,
9032264148L,64149L,64150L,64151L,64152L,64153L,64154L,64155L,64156L,64157L,
9032364158L,64159L,64160L,64161L,64162L,64163L,64164L,64165L,64166L,64167L,
9032464168L,64169L,64170L,64171L,64172L,64173L,64174L,64175L,64176L,64177L,
9032564178L,64179L,64180L,64181L,64182L,64183L,64184L,64185L,64186L,64187L,
9032664188L,64189L,64190L,64191L,64192L,64193L,64194L,64195L,64196L,64197L,
9032764198L,64199L,64200L,64201L,64202L,64203L,64204L,64205L,64206L,64207L,
9032864208L,64209L,64210L,64211L,64212L,64213L,64214L,64215L,64216L,64217L,
9032964218L,64219L,64220L,64221L,64222L,64223L,64224L,64225L,64226L,64227L,
9033064228L,64229L,64230L,64231L,64232L,64233L,64234L,64235L,64236L,64237L,
9033164238L,64239L,64240L,64241L,64242L,64243L,64244L,64245L,64246L,64247L,
9033264248L,64249L,64250L,64251L,64252L,64253L,64254L,64255L,64256L,64257L,
9033364258L,64259L,64260L,64261L,64262L,64263L,64264L,64265L,64266L,64267L,
9033464268L,64269L,64270L,64271L,64272L,64273L,64274L,64275L,64276L,64277L,
9033564278L,64279L,64280L,64281L,64282L,64283L,64284L,64285L,64286L,64287L,
9033664288L,64289L,64290L,64291L,64292L,64293L,64294L,64295L,64296L,64297L,
9033764298L,64299L,64300L,64301L,64302L,64303L,64304L,64305L,64306L,64307L,
9033864308L,64309L,64310L,64311L,64312L,64313L,64314L,64315L,64316L,64317L,
9033964318L,64319L,64320L,64321L,64322L,64323L,64324L,64325L,64326L,64327L,
9034064328L,64329L,64330L,64331L,64332L,64333L,64334L,64335L,64336L,64337L,
9034164338L,64339L,64340L,64341L,64342L,64343L,64344L,64345L,64346L,64347L,
9034264348L,64349L,64350L,64351L,64352L,64353L,64354L,64355L,64356L,64357L,
9034364358L,64359L,64360L,64361L,64362L,64363L,64364L,64365L,64366L,64367L,
9034464368L,64369L,64370L,64371L,64372L,64373L,64374L,64375L,64376L,64377L,
9034564378L,64379L,64380L,64381L,64382L,64383L,64384L,64385L,64386L,64387L,
9034664388L,64389L,64390L,64391L,64392L,64393L,64394L,64395L,64396L,64397L,
9034764398L,64399L,64400L,64401L,64402L,64403L,64404L,64405L,64406L,64407L,
9034864408L,64409L,64410L,64411L,64412L,64413L,64414L,64415L,64416L,64417L,
9034964418L,64419L,64420L,64421L,64422L,64423L,64424L,64425L,64426L,64427L,
9035064428L,64429L,64430L,64431L,64432L,64433L,64434L,64435L,64436L,64437L,
9035164438L,64439L,64440L,64441L,64442L,64443L,64444L,64445L,64446L,64447L,
9035264448L,64449L,64450L,64451L,64452L,64453L,64454L,64455L,64456L,64457L,
9035364458L,64459L,64460L,64461L,64462L,64463L,64464L,64465L,64466L,64467L,
9035464468L,64469L,64470L,64471L,64472L,64473L,64474L,64475L,64476L,64477L,
9035564478L,64479L,64480L,64481L,64482L,64483L,64484L,64485L,64486L,64487L,
9035664488L,64489L,64490L,64491L,64492L,64493L,64494L,64495L,64496L,64497L,
9035764498L,64499L,64500L,64501L,64502L,64503L,64504L,64505L,64506L,64507L,
9035864508L,64509L,64510L,64511L,64512L,64513L,64514L,64515L,64516L,64517L,
9035964518L,64519L,64520L,64521L,64522L,64523L,64524L,64525L,64526L,64527L,
9036064528L,64529L,64530L,64531L,64532L,64533L,64534L,64535L,64536L,64537L,
9036164538L,64539L,64540L,64541L,64542L,64543L,64544L,64545L,64546L,64547L,
9036264548L,64549L,64550L,64551L,64552L,64553L,64554L,64555L,64556L,64557L,
9036364558L,64559L,64560L,64561L,64562L,64563L,64564L,64565L,64566L,64567L,
9036464568L,64569L,64570L,64571L,64572L,64573L,64574L,64575L,64576L,64577L,
9036564578L,64579L,64580L,64581L,64582L,64583L,64584L,64585L,64586L,64587L,
9036664588L,64589L,64590L,64591L,64592L,64593L,64594L,64595L,64596L,64597L,
9036764598L,64599L,64600L,64601L,64602L,64603L,64604L,64605L,64606L,64607L,
9036864608L,64609L,64610L,64611L,64612L,64613L,64614L,64615L,64616L,64617L,
9036964618L,64619L,64620L,64621L,64622L,64623L,64624L,64625L,64626L,64627L,
9037064628L,64629L,64630L,64631L,64632L,64633L,64634L,64635L,64636L,64637L,
9037164638L,64639L,64640L,64641L,64642L,64643L,64644L,64645L,64646L,64647L,
9037264648L,64649L,64650L,64651L,64652L,64653L,64654L,64655L,64656L,64657L,
9037364658L,64659L,64660L,64661L,64662L,64663L,64664L,64665L,64666L,64667L,
9037464668L,64669L,64670L,64671L,64672L,64673L,64674L,64675L,64676L,64677L,
9037564678L,64679L,64680L,64681L,64682L,64683L,64684L,64685L,64686L,64687L,
9037664688L,64689L,64690L,64691L,64692L,64693L,64694L,64695L,64696L,64697L,
9037764698L,64699L,64700L,64701L,64702L,64703L,64704L,64705L,64706L,64707L,
9037864708L,64709L,64710L,64711L,64712L,64713L,64714L,64715L,64716L,64717L,
9037964718L,64719L,64720L,64721L,64722L,64723L,64724L,64725L,64726L,64727L,
9038064728L,64729L,64730L,64731L,64732L,64733L,64734L,64735L,64736L,64737L,
9038164738L,64739L,64740L,64741L,64742L,64743L,64744L,64745L,64746L,64747L,
9038264748L,64749L,64750L,64751L,64752L,64753L,64754L,64755L,64756L,64757L,
9038364758L,64759L,64760L,64761L,64762L,64763L,64764L,64765L,64766L,64767L,
9038464768L,64769L,64770L,64771L,64772L,64773L,64774L,64775L,64776L,64777L,
9038564778L,64779L,64780L,64781L,64782L,64783L,64784L,64785L,64786L,64787L,
9038664788L,64789L,64790L,64791L,64792L,64793L,64794L,64795L,64796L,64797L,
9038764798L,64799L,64800L,64801L,64802L,64803L,64804L,64805L,64806L,64807L,
9038864808L,64809L,64810L,64811L,64812L,64813L,64814L,64815L,64816L,64817L,
9038964818L,64819L,64820L,64821L,64822L,64823L,64824L,64825L,64826L,64827L,
9039064828L,64829L,64830L,64831L,64832L,64833L,64834L,64835L,64836L,64837L,
9039164838L,64839L,64840L,64841L,64842L,64843L,64844L,64845L,64846L,64847L,
9039264848L,64849L,64850L,64851L,64852L,64853L,64854L,64855L,64856L,64857L,
9039364858L,64859L,64860L,64861L,64862L,64863L,64864L,64865L,64866L,64867L,
9039464868L,64869L,64870L,64871L,64872L,64873L,64874L,64875L,64876L,64877L,
9039564878L,64879L,64880L,64881L,64882L,64883L,64884L,64885L,64886L,64887L,
9039664888L,64889L,64890L,64891L,64892L,64893L,64894L,64895L,64896L,64897L,
9039764898L,64899L,64900L,64901L,64902L,64903L,64904L,64905L,64906L,64907L,
9039864908L,64909L,64910L,64911L,64912L,64913L,64914L,64915L,64916L,64917L,
9039964918L,64919L,64920L,64921L,64922L,64923L,64924L,64925L,64926L,64927L,
9040064928L,64929L,64930L,64931L,64932L,64933L,64934L,64935L,64936L,64937L,
9040164938L,64939L,64940L,64941L,64942L,64943L,64944L,64945L,64946L,64947L,
9040264948L,64949L,64950L,64951L,64952L,64953L,64954L,64955L,64956L,64957L,
9040364958L,64959L,64960L,64961L,64962L,64963L,64964L,64965L,64966L,64967L,
9040464968L,64969L,64970L,64971L,64972L,64973L,64974L,64975L,64976L,64977L,
9040564978L,64979L,64980L,64981L,64982L,64983L,64984L,64985L,64986L,64987L,
9040664988L,64989L,64990L,64991L,64992L,64993L,64994L,64995L,64996L,64997L,
9040764998L,64999L,65000L,65001L,65002L,65003L,65004L,65005L,65006L,65007L,
9040865008L,65009L,65010L,65011L,65012L,65013L,65014L,65015L,65016L,65017L,
9040965018L,65019L,65020L,65021L,65022L,65023L,65024L,65025L,65026L,65027L,
9041065028L,65029L,65030L,65031L,65032L,65033L,65034L,65035L,65036L,65037L,
9041165038L,65039L,65040L,65041L,65042L,65043L,65044L,65045L,65046L,65047L,
9041265048L,65049L,65050L,65051L,65052L,65053L,65054L,65055L,65056L,65057L,
9041365058L,65059L,65060L,65061L,65062L,65063L,65064L,65065L,65066L,65067L,
9041465068L,65069L,65070L,65071L,65072L,65073L,65074L,65075L,65076L,65077L,
9041565078L,65079L,65080L,65081L,65082L,65083L,65084L,65085L,65086L,65087L,
9041665088L,65089L,65090L,65091L,65092L,65093L,65094L,65095L,65096L,65097L,
9041765098L,65099L,65100L,65101L,65102L,65103L,65104L,65105L,65106L,65107L,
9041865108L,65109L,65110L,65111L,65112L,65113L,65114L,65115L,65116L,65117L,
9041965118L,65119L,65120L,65121L,65122L,65123L,65124L,65125L,65126L,65127L,
9042065128L,65129L,65130L,65131L,65132L,65133L,65134L,65135L,65136L,65137L,
9042165138L,65139L,65140L,65141L,65142L,65143L,65144L,65145L,65146L,65147L,
9042265148L,65149L,65150L,65151L,65152L,65153L,65154L,65155L,65156L,65157L,
9042365158L,65159L,65160L,65161L,65162L,65163L,65164L,65165L,65166L,65167L,
9042465168L,65169L,65170L,65171L,65172L,65173L,65174L,65175L,65176L,65177L,
9042565178L,65179L,65180L,65181L,65182L,65183L,65184L,65185L,65186L,65187L,
9042665188L,65189L,65190L,65191L,65192L,65193L,65194L,65195L,65196L,65197L,
9042765198L,65199L,65200L,65201L,65202L,65203L,65204L,65205L,65206L,65207L,
9042865208L,65209L,65210L,65211L,65212L,65213L,65214L,65215L,65216L,65217L,
9042965218L,65219L,65220L,65221L,65222L,65223L,65224L,65225L,65226L,65227L,
9043065228L,65229L,65230L,65231L,65232L,65233L,65234L,65235L,65236L,65237L,
9043165238L,65239L,65240L,65241L,65242L,65243L,65244L,65245L,65246L,65247L,
9043265248L,65249L,65250L,65251L,65252L,65253L,65254L,65255L,65256L,65257L,
9043365258L,65259L,65260L,65261L,65262L,65263L,65264L,65265L,65266L,65267L,
9043465268L,65269L,65270L,65271L,65272L,65273L,65274L,65275L,65276L,65277L,
9043565278L,65279L,65280L,65281L,65282L,65283L,65284L,65285L,65286L,65287L,
9043665288L,65289L,65290L,65291L,65292L,65293L,65294L,65295L,65296L,65297L,
9043765298L,65299L,65300L,65301L,65302L,65303L,65304L,65305L,65306L,65307L,
9043865308L,65309L,65310L,65311L,65312L,65313L,65314L,65315L,65316L,65317L,
9043965318L,65319L,65320L,65321L,65322L,65323L,65324L,65325L,65326L,65327L,
9044065328L,65329L,65330L,65331L,65332L,65333L,65334L,65335L,65336L,65337L,
9044165338L,65339L,65340L,65341L,65342L,65343L,65344L,65313L,65314L,65315L,
9044265316L,65317L,65318L,65319L,65320L,65321L,65322L,65323L,65324L,65325L,
9044365326L,65327L,65328L,65329L,65330L,65331L,65332L,65333L,65334L,65335L,
9044465336L,65337L,65338L,65371L,65372L,65373L,65374L,65375L,65376L,65377L,
9044565378L,65379L,65380L,65381L,65382L,65383L,65384L,65385L,65386L,65387L,
9044665388L,65389L,65390L,65391L,65392L,65393L,65394L,65395L,65396L,65397L,
9044765398L,65399L,65400L,65401L,65402L,65403L,65404L,65405L,65406L,65407L,
9044865408L,65409L,65410L,65411L,65412L,65413L,65414L,65415L,65416L,65417L,
9044965418L,65419L,65420L,65421L,65422L,65423L,65424L,65425L,65426L,65427L,
9045065428L,65429L,65430L,65431L,65432L,65433L,65434L,65435L,65436L,65437L,
9045165438L,65439L,65440L,65441L,65442L,65443L,65444L,65445L,65446L,65447L,
9045265448L,65449L,65450L,65451L,65452L,65453L,65454L,65455L,65456L,65457L,
9045365458L,65459L,65460L,65461L,65462L,65463L,65464L,65465L,65466L,65467L,
9045465468L,65469L,65470L,65471L,65472L,65473L,65474L,65475L,65476L,65477L,
9045565478L,65479L,65480L,65481L,65482L,65483L,65484L,65485L,65486L,65487L,
9045665488L,65489L,65490L,65491L,65492L,65493L,65494L,65495L,65496L,65497L,
9045765498L,65499L,65500L,65501L,65502L,65503L,65504L,65505L,65506L,65507L,
9045865508L,65509L,65510L,65511L,65512L,65513L,65514L,65515L,65516L,65517L,
9045965518L,65519L,65520L,65521L,65522L,65523L,65524L,65525L,65526L,65527L,
9046065528L,65529L,65530L,65531L,65532L,65533L,65534L,65535L,
90461};
90462#endif
90463/*
90464 * Bitstream decoder.
90465 */
90466
90467/* #include duk_internal.h -> already included */
90468
90469/* Decode 'bits' bits from the input stream (bits must be 1...24).
90470 * When reading past bitstream end, zeroes are shifted in. The result
90471 * is signed to match duk_bd_decode_flagged.
90472 */
90473DUK_INTERNAL duk_uint32_t duk_bd_decode(duk_bitdecoder_ctx *ctx, duk_small_int_t bits) {
90474 duk_small_int_t shift;
90475 duk_uint32_t mask;
90476 duk_uint32_t tmp;
90477
90478 /* Note: cannot read more than 24 bits without possibly shifting top bits out.
90479 * Fixable, but adds complexity.
90480 */
90481 DUK_ASSERT(bits >= 1 && bits <= 24);
90482
90483 while (ctx->currbits < bits) {
90484#if 0
90485 DUK_DDD(DUK_DDDPRINT("decode_bits: shift more data (bits=%ld, currbits=%ld)",
90486 (long) bits, (long) ctx->currbits));
90487#endif
90488 ctx->currval <<= 8;
90489 if (ctx->offset < ctx->length) {
90490 /* If ctx->offset >= ctx->length, we "shift zeroes in"
90491 * instead of croaking.
90492 */
90493 ctx->currval |= ctx->data[ctx->offset++];
90494 }
90495 ctx->currbits += 8;
90496 }
90497#if 0
90498 DUK_DDD(DUK_DDDPRINT("decode_bits: bits=%ld, currbits=%ld, currval=0x%08lx",
90499 (long) bits, (long) ctx->currbits, (unsigned long) ctx->currval));
90500#endif
90501
90502 /* Extract 'top' bits of currval; note that the extracted bits do not need
90503 * to be cleared, we just ignore them on next round.
90504 */
90505 shift = ctx->currbits - bits;
90506 mask = (1 << bits) - 1;
90507 tmp = (ctx->currval >> shift) & mask;
90508 ctx->currbits = shift; /* remaining */
90509
90510#if 0
90511 DUK_DDD(DUK_DDDPRINT("decode_bits: %ld bits -> 0x%08lx (%ld), currbits=%ld, currval=0x%08lx",
90512 (long) bits, (unsigned long) tmp, (long) tmp, (long) ctx->currbits, (unsigned long) ctx->currval));
90513#endif
90514
90515 return tmp;
90516}
90517
90518DUK_INTERNAL duk_small_uint_t duk_bd_decode_flag(duk_bitdecoder_ctx *ctx) {
90519 return (duk_small_uint_t) duk_bd_decode(ctx, 1);
90520}
90521
90522/* Decode a one-bit flag, and if set, decode a value of 'bits', otherwise return
90523 * default value. Return value is signed so that negative marker value can be
90524 * used by caller as a "not present" value.
90525 */
90526DUK_INTERNAL duk_uint32_t duk_bd_decode_flagged(duk_bitdecoder_ctx *ctx, duk_small_int_t bits, duk_uint32_t def_value) {
90527 if (duk_bd_decode_flag(ctx)) {
90528 return duk_bd_decode(ctx, bits);
90529 } else {
90530 return def_value;
90531 }
90532}
90533
90534/* Shared varint encoding. Match dukutil.py BitEncode.varuint(). */
90535DUK_INTERNAL duk_uint32_t duk_bd_decode_varuint(duk_bitdecoder_ctx *ctx) {
90536 duk_small_uint_t t;
90537
90538 /* The bit encoding choices here are based on manual testing against
90539 * the actual varuints generated by genbuiltins.py.
90540 */
90541 switch (duk_bd_decode(ctx, 2)) {
90542 case 0:
90543 return 0; /* [0,0] */
90544 case 1:
90545 return duk_bd_decode(ctx, 2) + 1; /* [1,4] */
90546 case 2:
90547 return duk_bd_decode(ctx, 5) + 5; /* [5,36] */
90548 default:
90549 t = duk_bd_decode(ctx, 7);
90550 if (t == 0) {
90551 return duk_bd_decode(ctx, 20);
90552 }
90553 return (t - 1) + 37; /* [37,163] */
90554 }
90555}
90556
90557/* Decode a bit packed string from a custom format used by genbuiltins.py.
90558 * This function is here because it's used for both heap and thread inits.
90559 * Caller must supply the output buffer whose size is NOT checked!
90560 */
90561
90562#define DUK__BITPACK_LETTER_LIMIT 26
90563#define DUK__BITPACK_LOOKUP1 26
90564#define DUK__BITPACK_LOOKUP2 27
90565#define DUK__BITPACK_SWITCH1 28
90566#define DUK__BITPACK_SWITCH 29
90567#define DUK__BITPACK_UNUSED1 30
90568#define DUK__BITPACK_EIGHTBIT 31
90569
90570DUK_LOCAL const duk_uint8_t duk__bitpacked_lookup[16] = {
90571 DUK_ASC_0, DUK_ASC_1, DUK_ASC_2, DUK_ASC_3,
90572 DUK_ASC_4, DUK_ASC_5, DUK_ASC_6, DUK_ASC_7,
90573 DUK_ASC_8, DUK_ASC_9, DUK_ASC_UNDERSCORE, DUK_ASC_SPACE,
90574 0xff, 0x80, DUK_ASC_DOUBLEQUOTE, DUK_ASC_LCURLY
90575};
90576
90577DUK_INTERNAL duk_small_uint_t duk_bd_decode_bitpacked_string(duk_bitdecoder_ctx *bd, duk_uint8_t *out) {
90578 duk_small_uint_t len;
90579 duk_small_uint_t mode;
90580 duk_small_uint_t t;
90581 duk_small_uint_t i;
90582
90583 len = duk_bd_decode(bd, 5);
90584 if (len == 31) {
90585 len = duk_bd_decode(bd, 8); /* Support up to 256 bytes; rare. */
90586 }
90587
90588 mode = 32; /* 0 = uppercase, 32 = lowercase (= 'a' - 'A') */
90589 for (i = 0; i < len; i++) {
90590 t = duk_bd_decode(bd, 5);
90591 if (t < DUK__BITPACK_LETTER_LIMIT) {
90592 t = t + DUK_ASC_UC_A + mode;
90593 } else if (t == DUK__BITPACK_LOOKUP1) {
90594 t = duk__bitpacked_lookup[duk_bd_decode(bd, 3)];
90595 } else if (t == DUK__BITPACK_LOOKUP2) {
90596 t = duk__bitpacked_lookup[8 + duk_bd_decode(bd, 3)];
90597 } else if (t == DUK__BITPACK_SWITCH1) {
90598 t = duk_bd_decode(bd, 5);
90599 DUK_ASSERT_DISABLE(t >= 0); /* unsigned */
90600 DUK_ASSERT(t <= 25);
90601 t = t + DUK_ASC_UC_A + (mode ^ 32);
90602 } else if (t == DUK__BITPACK_SWITCH) {
90603 mode = mode ^ 32;
90604 t = duk_bd_decode(bd, 5);
90605 DUK_ASSERT_DISABLE(t >= 0);
90606 DUK_ASSERT(t <= 25);
90607 t = t + DUK_ASC_UC_A + mode;
90608 } else if (t == DUK__BITPACK_EIGHTBIT) {
90609 t = duk_bd_decode(bd, 8);
90610 }
90611 out[i] = (duk_uint8_t) t;
90612 }
90613
90614 return len;
90615}
90616
90617/* automatic undefs */
90618#undef DUK__BITPACK_EIGHTBIT
90619#undef DUK__BITPACK_LETTER_LIMIT
90620#undef DUK__BITPACK_LOOKUP1
90621#undef DUK__BITPACK_LOOKUP2
90622#undef DUK__BITPACK_SWITCH
90623#undef DUK__BITPACK_SWITCH1
90624#undef DUK__BITPACK_UNUSED1
90625/*
90626 * Bitstream encoder.
90627 */
90628
90629/* #include duk_internal.h -> already included */
90630
90631DUK_INTERNAL void duk_be_encode(duk_bitencoder_ctx *ctx, duk_uint32_t data, duk_small_int_t bits) {
90632 duk_uint8_t tmp;
90633
90634 DUK_ASSERT(ctx != NULL);
90635 DUK_ASSERT(ctx->currbits < 8);
90636
90637 /* This limitation would be fixable but adds unnecessary complexity. */
90638 DUK_ASSERT(bits >= 1 && bits <= 24);
90639
90640 ctx->currval = (ctx->currval << bits) | data;
90641 ctx->currbits += bits;
90642
90643 while (ctx->currbits >= 8) {
90644 if (ctx->offset < ctx->length) {
90645 tmp = (duk_uint8_t) ((ctx->currval >> (ctx->currbits - 8)) & 0xff);
90646 ctx->data[ctx->offset++] = tmp;
90647 } else {
90648 /* If buffer has been exhausted, truncate bitstream */
90649 ctx->truncated = 1;
90650 }
90651
90652 ctx->currbits -= 8;
90653 }
90654}
90655
90656DUK_INTERNAL void duk_be_finish(duk_bitencoder_ctx *ctx) {
90657 duk_small_int_t npad;
90658
90659 DUK_ASSERT(ctx != NULL);
90660 DUK_ASSERT(ctx->currbits < 8);
90661
90662 npad = (duk_small_int_t) (8 - ctx->currbits);
90663 if (npad > 0) {
90664 duk_be_encode(ctx, 0, npad);
90665 }
90666 DUK_ASSERT(ctx->currbits == 0);
90667}
90668/*
90669 * Fast buffer writer with spare management.
90670 */
90671
90672/* #include duk_internal.h -> already included */
90673
90674/*
90675 * Macro support functions (use only macros in calling code)
90676 */
90677
90678DUK_LOCAL void duk__bw_update_ptrs(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t curr_offset, duk_size_t new_length) {
90679 duk_uint8_t *p;
90680
90681 DUK_ASSERT(thr != NULL);
90682 DUK_ASSERT(bw_ctx != NULL);
90683 DUK_UNREF(thr);
90684
90685 p = (duk_uint8_t *) DUK_HBUFFER_DYNAMIC_GET_DATA_PTR(thr->heap, bw_ctx->buf);
90686 DUK_ASSERT(p != NULL || (DUK_HBUFFER_DYNAMIC_GET_SIZE(bw_ctx->buf) == 0 && curr_offset == 0 && new_length == 0));
90687 bw_ctx->p = p + curr_offset;
90688 bw_ctx->p_base = p;
90689 bw_ctx->p_limit = p + new_length;
90690}
90691
90692DUK_INTERNAL void duk_bw_init(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_hbuffer_dynamic *h_buf) {
90693
90694 DUK_ASSERT(thr != NULL);
90695 DUK_ASSERT(bw_ctx != NULL);
90696 DUK_ASSERT(h_buf != NULL);
90697 DUK_UNREF(thr);
90698
90699 bw_ctx->buf = h_buf;
90700 duk__bw_update_ptrs(thr, bw_ctx, 0, DUK_HBUFFER_DYNAMIC_GET_SIZE(h_buf));
90701}
90702
90703DUK_INTERNAL void duk_bw_init_pushbuf(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t buf_size) {
90704 duk_context *ctx;
90705
90706 DUK_ASSERT(thr != NULL);
90707 DUK_ASSERT(bw_ctx != NULL);
90708 ctx = (duk_context *) thr;
90709
90710 (void) duk_push_dynamic_buffer(ctx, buf_size);
90711 bw_ctx->buf = (duk_hbuffer_dynamic *) duk_known_hbuffer(ctx, -1);
90712 duk__bw_update_ptrs(thr, bw_ctx, 0, buf_size);
90713}
90714
90715/* Resize target buffer for requested size. Called by the macro only when the
90716 * fast path test (= there is space) fails.
90717 */
90718DUK_INTERNAL duk_uint8_t *duk_bw_resize(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx, duk_size_t sz) {
90719 duk_size_t curr_off;
90720 duk_size_t add_sz;
90721 duk_size_t new_sz;
90722
90723 DUK_ASSERT(thr != NULL);
90724 DUK_ASSERT(bw_ctx != NULL);
90725
90726 /* We could do this operation without caller updating bw_ctx->ptr,
90727 * but by writing it back here we can share code better.
90728 */
90729
90730 curr_off = (duk_size_t) (bw_ctx->p - bw_ctx->p_base);
90731 add_sz = (curr_off >> DUK_BW_SPARE_SHIFT) + DUK_BW_SPARE_ADD;
90732 new_sz = curr_off + sz + add_sz;
90733 if (new_sz < curr_off) {
90734 /* overflow */
90735 DUK_ERROR_RANGE(thr, DUK_STR_BUFFER_TOO_LONG);
90736 return NULL; /* not reachable */
90737 }
90738#if 0 /* for manual torture testing: tight allocation, useful with valgrind */
90739 new_sz = curr_off + sz;
90740#endif
90741
90742 /* This is important to ensure dynamic buffer data pointer is not
90743 * NULL (which is possible if buffer size is zero), which in turn
90744 * causes portability issues with e.g. memmove() and memcpy().
90745 */
90746 DUK_ASSERT(new_sz >= 1);
90747
90748 DUK_DD(DUK_DDPRINT("resize bufferwriter from %ld to %ld (add_sz=%ld)", (long) curr_off, (long) new_sz, (long) add_sz));
90749
90750 duk_hbuffer_resize(thr, bw_ctx->buf, new_sz);
90751 duk__bw_update_ptrs(thr, bw_ctx, curr_off, new_sz);
90752 return bw_ctx->p;
90753}
90754
90755/* Make buffer compact, matching current written size. */
90756DUK_INTERNAL void duk_bw_compact(duk_hthread *thr, duk_bufwriter_ctx *bw_ctx) {
90757 duk_size_t len;
90758
90759 DUK_ASSERT(thr != NULL);
90760 DUK_ASSERT(bw_ctx != NULL);
90761 DUK_UNREF(thr);
90762
90763 len = (duk_size_t) (bw_ctx->p - bw_ctx->p_base);
90764 duk_hbuffer_resize(thr, bw_ctx->buf, len);
90765 duk__bw_update_ptrs(thr, bw_ctx, len, len);
90766}
90767
90768DUK_INTERNAL void duk_bw_write_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len) {
90769 duk_uint8_t *p_base;
90770
90771 DUK_ASSERT(thr != NULL);
90772 DUK_ASSERT(bw != NULL);
90773 DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
90774 DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
90775 DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
90776 DUK_UNREF(thr);
90777
90778 p_base = bw->p_base;
90779 DUK_MEMCPY((void *) bw->p,
90780 (const void *) (p_base + src_off),
90781 (size_t) len);
90782 bw->p += len;
90783}
90784
90785DUK_INTERNAL void duk_bw_write_ensure_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t src_off, duk_size_t len) {
90786 DUK_ASSERT(thr != NULL);
90787 DUK_ASSERT(bw != NULL);
90788 DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
90789 DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
90790 DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
90791 DUK_UNREF(thr);
90792
90793 DUK_BW_ENSURE(thr, bw, len);
90794 duk_bw_write_raw_slice(thr, bw, src_off, len);
90795}
90796
90797DUK_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) {
90798 duk_uint8_t *p_base;
90799 duk_size_t buf_sz, move_sz;
90800
90801 DUK_ASSERT(thr != NULL);
90802 DUK_ASSERT(bw != NULL);
90803 DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw));
90804 DUK_ASSERT(buf != NULL);
90805 DUK_UNREF(thr);
90806
90807 p_base = bw->p_base;
90808 buf_sz = bw->p - p_base;
90809 move_sz = buf_sz - dst_off;
90810
90811 DUK_ASSERT(p_base != NULL); /* buffer size is >= 1 */
90812 DUK_MEMMOVE((void *) (p_base + dst_off + len),
90813 (const void *) (p_base + dst_off),
90814 (size_t) move_sz);
90815 DUK_MEMCPY((void *) (p_base + dst_off),
90816 (const void *) buf,
90817 (size_t) len);
90818 bw->p += len;
90819}
90820
90821DUK_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) {
90822 DUK_ASSERT(thr != NULL);
90823 DUK_ASSERT(bw != NULL);
90824 DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw));
90825 DUK_ASSERT(buf != NULL);
90826 DUK_UNREF(thr);
90827
90828 DUK_BW_ENSURE(thr, bw, len);
90829 duk_bw_insert_raw_bytes(thr, bw, dst_off, buf, len);
90830}
90831
90832DUK_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) {
90833 duk_uint8_t *p_base;
90834 duk_size_t buf_sz, move_sz;
90835
90836 DUK_ASSERT(thr != NULL);
90837 DUK_ASSERT(bw != NULL);
90838 DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw));
90839 DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
90840 DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
90841 DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
90842 DUK_UNREF(thr);
90843
90844 p_base = bw->p_base;
90845
90846 /* Don't support "straddled" source now. */
90847 DUK_ASSERT(dst_off <= src_off || dst_off >= src_off + len);
90848
90849 if (dst_off <= src_off) {
90850 /* Target is before source. Source offset is expressed as
90851 * a "before change" offset. Account for the memmove.
90852 */
90853 src_off += len;
90854 }
90855
90856 buf_sz = bw->p - p_base;
90857 move_sz = buf_sz - dst_off;
90858
90859 DUK_ASSERT(p_base != NULL); /* buffer size is >= 1 */
90860 DUK_MEMMOVE((void *) (p_base + dst_off + len),
90861 (const void *) (p_base + dst_off),
90862 (size_t) move_sz);
90863 DUK_MEMCPY((void *) (p_base + dst_off),
90864 (const void *) (p_base + src_off),
90865 (size_t) len);
90866 bw->p += len;
90867}
90868
90869DUK_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) {
90870 DUK_ASSERT(thr != NULL);
90871 DUK_ASSERT(bw != NULL);
90872 DUK_ASSERT(dst_off <= DUK_BW_GET_SIZE(thr, bw));
90873 DUK_ASSERT(src_off <= DUK_BW_GET_SIZE(thr, bw));
90874 DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
90875 DUK_ASSERT(src_off + len <= DUK_BW_GET_SIZE(thr, bw));
90876 DUK_UNREF(thr);
90877
90878 /* Don't support "straddled" source now. */
90879 DUK_ASSERT(dst_off <= src_off || dst_off >= src_off + len);
90880
90881 DUK_BW_ENSURE(thr, bw, len);
90882 duk_bw_insert_raw_slice(thr, bw, dst_off, src_off, len);
90883}
90884
90885DUK_INTERNAL duk_uint8_t *duk_bw_insert_raw_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len) {
90886 duk_uint8_t *p_base, *p_dst, *p_src;
90887 duk_size_t buf_sz, move_sz;
90888
90889 DUK_ASSERT(thr != NULL);
90890 DUK_ASSERT(bw != NULL);
90891 DUK_ASSERT(off <= DUK_BW_GET_SIZE(thr, bw));
90892 DUK_UNREF(thr);
90893
90894 p_base = bw->p_base;
90895 buf_sz = bw->p - p_base;
90896 move_sz = buf_sz - off;
90897 p_dst = p_base + off + len;
90898 p_src = p_base + off;
90899 DUK_MEMMOVE((void *) p_dst, (const void *) p_src, (size_t) move_sz);
90900 return p_src; /* point to start of 'reserved area' */
90901}
90902
90903DUK_INTERNAL duk_uint8_t *duk_bw_insert_ensure_area(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len) {
90904 DUK_ASSERT(thr != NULL);
90905 DUK_ASSERT(bw != NULL);
90906 DUK_ASSERT(off <= DUK_BW_GET_SIZE(thr, bw));
90907 DUK_UNREF(thr);
90908
90909 DUK_BW_ENSURE(thr, bw, len);
90910 return duk_bw_insert_raw_area(thr, bw, off, len);
90911}
90912
90913DUK_INTERNAL void duk_bw_remove_raw_slice(duk_hthread *thr, duk_bufwriter_ctx *bw, duk_size_t off, duk_size_t len) {
90914 duk_size_t move_sz;
90915
90916 duk_uint8_t *p_base;
90917 duk_uint8_t *p_src;
90918 duk_uint8_t *p_dst;
90919
90920 DUK_ASSERT(thr != NULL);
90921 DUK_ASSERT(bw != NULL);
90922 DUK_ASSERT(off <= DUK_BW_GET_SIZE(thr, bw));
90923 DUK_ASSERT(len <= DUK_BW_GET_SIZE(thr, bw));
90924 DUK_ASSERT(off + len <= DUK_BW_GET_SIZE(thr, bw));
90925 DUK_UNREF(thr);
90926
90927 p_base = bw->p_base;
90928 p_dst = p_base + off;
90929 p_src = p_dst + len;
90930 move_sz = (duk_size_t) (bw->p - p_src);
90931 DUK_MEMMOVE((void *) p_dst,
90932 (const void *) p_src,
90933 (size_t) move_sz);
90934 bw->p -= len;
90935}
90936
90937/*
90938 * Macro support functions for reading/writing raw data.
90939 *
90940 * These are done using mempcy to ensure they're valid even for unaligned
90941 * reads/writes on platforms where alignment counts. On x86 at least gcc
90942 * is able to compile these into a bswap+mov. "Always inline" is used to
90943 * ensure these macros compile to minimal code.
90944 *
90945 * Not really bufwriter related, but currently used together.
90946 */
90947
90948DUK_INTERNAL DUK_ALWAYS_INLINE duk_uint16_t duk_raw_read_u16_be(duk_uint8_t **p) {
90949 union {
90950 duk_uint8_t b[2];
90951 duk_uint16_t x;
90952 } u;
90953
90954 DUK_MEMCPY((void *) u.b, (const void *) (*p), (size_t) 2);
90955 u.x = DUK_NTOH16(u.x);
90956 *p += 2;
90957 return u.x;
90958}
90959
90960DUK_INTERNAL DUK_ALWAYS_INLINE duk_uint32_t duk_raw_read_u32_be(duk_uint8_t **p) {
90961 union {
90962 duk_uint8_t b[4];
90963 duk_uint32_t x;
90964 } u;
90965
90966 DUK_MEMCPY((void *) u.b, (const void *) (*p), (size_t) 4);
90967 u.x = DUK_NTOH32(u.x);
90968 *p += 4;
90969 return u.x;
90970}
90971
90972DUK_INTERNAL DUK_ALWAYS_INLINE duk_double_t duk_raw_read_double_be(duk_uint8_t **p) {
90974 union {
90975 duk_uint8_t b[4];
90976 duk_uint32_t x;
90977 } u;
90978
90979 DUK_MEMCPY((void *) u.b, (const void *) (*p), (size_t) 4);
90980 u.x = DUK_NTOH32(u.x);
90981 du.ui[DUK_DBL_IDX_UI0] = u.x;
90982 DUK_MEMCPY((void *) u.b, (const void *) (*p + 4), (size_t) 4);
90983 u.x = DUK_NTOH32(u.x);
90984 du.ui[DUK_DBL_IDX_UI1] = u.x;
90985 *p += 8;
90986
90987 return du.d;
90988}
90989
90990DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_u16_be(duk_uint8_t **p, duk_uint16_t val) {
90991 union {
90992 duk_uint8_t b[2];
90993 duk_uint16_t x;
90994 } u;
90995
90996 u.x = DUK_HTON16(val);
90997 DUK_MEMCPY((void *) (*p), (const void *) u.b, (size_t) 2);
90998 *p += 2;
90999}
91000
91001DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_u32_be(duk_uint8_t **p, duk_uint32_t val) {
91002 union {
91003 duk_uint8_t b[4];
91004 duk_uint32_t x;
91005 } u;
91006
91007 u.x = DUK_HTON32(val);
91008 DUK_MEMCPY((void *) (*p), (const void *) u.b, (size_t) 4);
91009 *p += 4;
91010}
91011
91012DUK_INTERNAL DUK_ALWAYS_INLINE void duk_raw_write_double_be(duk_uint8_t **p, duk_double_t val) {
91014 union {
91015 duk_uint8_t b[4];
91016 duk_uint32_t x;
91017 } u;
91018
91019 du.d = val;
91020 u.x = du.ui[DUK_DBL_IDX_UI0];
91021 u.x = DUK_HTON32(u.x);
91022 DUK_MEMCPY((void *) (*p), (const void *) u.b, (size_t) 4);
91023 u.x = du.ui[DUK_DBL_IDX_UI1];
91024 u.x = DUK_HTON32(u.x);
91025 DUK_MEMCPY((void *) (*p + 4), (const void *) u.b, (size_t) 4);
91026 *p += 8;
91027}
91028/*
91029 * Hash function duk_util_hashbytes().
91030 *
91031 * Currently, 32-bit MurmurHash2.
91032 *
91033 * Don't rely on specific hash values; hash function may be endianness
91034 * dependent, for instance.
91035 */
91036
91037/* #include duk_internal.h -> already included */
91038
91039#if defined(DUK_USE_STRHASH_DENSE)
91040/* 'magic' constants for Murmurhash2 */
91041#define DUK__MAGIC_M ((duk_uint32_t) 0x5bd1e995UL)
91042#define DUK__MAGIC_R 24
91043
91044DUK_INTERNAL duk_uint32_t duk_util_hashbytes(const duk_uint8_t *data, duk_size_t len, duk_uint32_t seed) {
91045 duk_uint32_t h = seed ^ ((duk_uint32_t) len);
91046
91047 while (len >= 4) {
91048 /* Portability workaround is required for platforms without
91049 * unaligned access. The replacement code emulates little
91050 * endian access even on big endian architectures, which is
91051 * OK as long as it is consistent for a build.
91052 */
91053#if defined(DUK_USE_HASHBYTES_UNALIGNED_U32_ACCESS)
91054 duk_uint32_t k = *((const duk_uint32_t *) (const void *) data);
91055#else
91056 duk_uint32_t k = ((duk_uint32_t) data[0]) |
91057 (((duk_uint32_t) data[1]) << 8) |
91058 (((duk_uint32_t) data[2]) << 16) |
91059 (((duk_uint32_t) data[3]) << 24);
91060#endif
91061
91062 k *= DUK__MAGIC_M;
91063 k ^= k >> DUK__MAGIC_R;
91064 k *= DUK__MAGIC_M;
91065 h *= DUK__MAGIC_M;
91066 h ^= k;
91067 data += 4;
91068 len -= 4;
91069 }
91070
91071 switch (len) {
91072 case 3: h ^= data[2] << 16;
91073 case 2: h ^= data[1] << 8;
91074 case 1: h ^= data[0];
91075 h *= DUK__MAGIC_M;
91076 }
91077
91078 h ^= h >> 13;
91079 h *= DUK__MAGIC_M;
91080 h ^= h >> 15;
91081
91082 return h;
91083}
91084#endif /* DUK_USE_STRHASH_DENSE */
91085
91086/* automatic undefs */
91087#undef DUK__MAGIC_M
91088#undef DUK__MAGIC_R
91089/*
91090 * A tiny random number generator used for Math.random() and other internals.
91091 *
91092 * Default algorithm is xoroshiro128+: http://xoroshiro.di.unimi.it/xoroshiro128plus.c
91093 * with SplitMix64 seed preparation: http://xorshift.di.unimi.it/splitmix64.c.
91094 *
91095 * Low memory targets and targets without 64-bit types use a slightly smaller
91096 * (but slower) algorithm by Adi Shamir:
91097 * http://www.woodmann.com/forum/archive/index.php/t-3100.html.
91098 *
91099 */
91100
91101/* #include duk_internal.h -> already included */
91102
91103#if !defined(DUK_USE_GET_RANDOM_DOUBLE)
91104
91105#if defined(DUK_USE_PREFER_SIZE) || !defined(DUK_USE_64BIT_OPS)
91106#define DUK__RANDOM_SHAMIR3OP
91107#else
91108#define DUK__RANDOM_XOROSHIRO128PLUS
91109#endif
91110
91111#if defined(DUK__RANDOM_SHAMIR3OP)
91112#define DUK__UPDATE_RND(rnd) do { \
91113 (rnd) += ((rnd) * (rnd)) | 0x05UL; \
91114 (rnd) = ((rnd) & 0xffffffffUL); /* if duk_uint32_t is exactly 32 bits, this is a NOP */ \
91115 } while (0)
91116
91117#define DUK__RND_BIT(rnd) ((rnd) >> 31) /* only use the highest bit */
91118
91119DUK_INTERNAL void duk_util_tinyrandom_prepare_seed(duk_hthread *thr) {
91120 DUK_UNREF(thr); /* Nothing now. */
91121}
91122
91123DUK_INTERNAL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr) {
91124 duk_double_t t;
91125 duk_small_int_t n;
91126 duk_uint32_t rnd;
91127
91128 rnd = thr->heap->rnd_state;
91129
91130 n = 53; /* enough to cover the whole mantissa */
91131 t = 0.0;
91132
91133 do {
91134 DUK__UPDATE_RND(rnd);
91135 t += DUK__RND_BIT(rnd);
91136 t /= 2.0;
91137 } while (--n);
91138
91139 thr->heap->rnd_state = rnd;
91140
91141 DUK_ASSERT(t >= (duk_double_t) 0.0);
91142 DUK_ASSERT(t < (duk_double_t) 1.0);
91143
91144 return t;
91145}
91146#endif /* DUK__RANDOM_SHAMIR3OP */
91147
91148#if defined(DUK__RANDOM_XOROSHIRO128PLUS)
91149DUK_LOCAL DUK_ALWAYS_INLINE duk_uint64_t duk__rnd_splitmix64(duk_uint64_t *x) {
91150 duk_uint64_t z;
91151 z = (*x += 0x9E3779B97F4A7C15ULL);
91152 z = (z ^ (z >> 30U)) * 0xBF58476D1CE4E5B9ULL;
91153 z = (z ^ (z >> 27U)) * 0x94D049BB133111EBULL;
91154 return z ^ (z >> 31U);
91155}
91156
91157DUK_LOCAL DUK_ALWAYS_INLINE duk_uint64_t duk__rnd_rotl(const duk_uint64_t x, duk_small_uint_t k) {
91158 return (x << k) | (x >> (64U - k));
91159}
91160
91161DUK_LOCAL DUK_ALWAYS_INLINE duk_uint64_t duk__xoroshiro128plus(duk_uint64_t *s) {
91162 duk_uint64_t s0;
91163 duk_uint64_t s1;
91164 duk_uint64_t res;
91165
91166 s0 = s[0];
91167 s1 = s[1];
91168 res = s0 + s1;
91169 s1 ^= s0;
91170 s[0] = duk__rnd_rotl(s0, 55) ^ s1 ^ (s1 << 14U);
91171 s[1] = duk__rnd_rotl(s1, 36);
91172
91173 return res;
91174}
91175
91176DUK_INTERNAL void duk_util_tinyrandom_prepare_seed(duk_hthread *thr) {
91177 duk_small_uint_t i;
91178 duk_uint64_t x;
91179
91180 /* Mix both halves of the initial seed with SplitMix64. The intent
91181 * is to ensure that very similar raw seeds (which is usually the case
91182 * because current seed is Date.now()) result in different xoroshiro128+
91183 * seeds.
91184 */
91185 x = thr->heap->rnd_state[0]; /* Only [0] is used as input here. */
91186 for (i = 0; i < 64; i++) {
91187 thr->heap->rnd_state[i & 0x01] = duk__rnd_splitmix64(&x); /* Keep last 2 values. */
91188 }
91189}
91190
91191DUK_INTERNAL duk_double_t duk_util_tinyrandom_get_double(duk_hthread *thr) {
91192 duk_uint64_t v;
91194
91195 /* For big and little endian the integer and IEEE double byte order
91196 * is the same so a direct assignment works. For mixed endian the
91197 * 32-bit parts must be swapped.
91198 */
91199 v = (0x3ffULL << 52U) | (duk__xoroshiro128plus((duk_uint64_t *) thr->heap->rnd_state) >> 12U);
91200 du.ull[0] = v;
91201#if defined(DUK_USE_DOUBLE_ME)
91202 do {
91203 duk_uint32_t tmp;
91204 tmp = du.ui[0];
91205 du.ui[0] = du.ui[1];
91206 du.ui[1] = tmp;
91207 } while (0);
91208#endif
91209 return du.d - 1.0;
91210}
91211#endif /* DUK__RANDOM_XOROSHIRO128PLUS */
91212
91213#endif /* !DUK_USE_GET_RANDOM_DOUBLE */
91214
91215/* automatic undefs */
91216#undef DUK__RANDOM_SHAMIR3OP
91217#undef DUK__RANDOM_XOROSHIRO128PLUS
91218#undef DUK__RND_BIT
91219#undef DUK__UPDATE_RND
Definition duktape.h:224
Definition duktape.h:230
Definition duktape.c:7728
Definition Viewer.h:139